mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 20:30:50 +08:00 
			
		
		
		
	
							
								
								
									
										46
									
								
								build.cake
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								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;	
 | 
			
		||||
}
 | 
			
		||||
@@ -7,7 +7,7 @@ namespace Ocelot.Authorisation
 | 
			
		||||
{
 | 
			
		||||
    using Infrastructure.Claims.Parser;
 | 
			
		||||
 | 
			
		||||
    public class ClaimsAuthoriser : IAuthoriser
 | 
			
		||||
    public class ClaimsAuthoriser : IClaimsAuthoriser
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IClaimsParser _claimsParser;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,8 @@ namespace Ocelot.Authorisation
 | 
			
		||||
{
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
    public interface IAuthoriser
 | 
			
		||||
    public interface IClaimsAuthoriser
 | 
			
		||||
    {
 | 
			
		||||
        Response<bool> Authorise(ClaimsPrincipal claimsPrincipal,
 | 
			
		||||
            Dictionary<string, string> routeClaimsRequirement);
 | 
			
		||||
        Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, Dictionary<string, string> routeClaimsRequirement);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/Ocelot/Authorisation/IScopesAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Ocelot/Authorisation/IScopesAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Authorisation
 | 
			
		||||
{
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
    public interface IScopesAuthoriser
 | 
			
		||||
    {
 | 
			
		||||
        Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, List<string> routeAllowedScopes);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<AuthorisationMiddleware>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -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<Error>
 | 
			
		||||
                    {
 | 
			
		||||
                        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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								src/Ocelot/Authorisation/ScopeNotAuthorisedError.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Ocelot/Authorisation/ScopeNotAuthorisedError.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Authorisation
 | 
			
		||||
{
 | 
			
		||||
    public class ScopeNotAuthorisedError : Error
 | 
			
		||||
    {
 | 
			
		||||
        public ScopeNotAuthorisedError(string message) 
 | 
			
		||||
            : base(message, OcelotErrorCode.ScopeNotAuthorisedError)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								src/Ocelot/Authorisation/ScopesAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/Ocelot/Authorisation/ScopesAuthoriser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<bool> Authorise(ClaimsPrincipal claimsPrincipal, List<string> routeAllowedScopes)
 | 
			
		||||
        {
 | 
			
		||||
            if (routeAllowedScopes == null || routeAllowedScopes.Count == 0)
 | 
			
		||||
            {
 | 
			
		||||
                return new OkResponse<bool>(true);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var values = _claimsParser.GetValuesByClaimType(claimsPrincipal.Claims, JwtClaimTypes.Scope);
 | 
			
		||||
 | 
			
		||||
            if (values.IsError)
 | 
			
		||||
            {
 | 
			
		||||
                return new ErrorResponse<bool>(values.Errors);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var userScopes = values.Data;
 | 
			
		||||
 | 
			
		||||
            List<string> matchesScopes = routeAllowedScopes.Intersect(userScopes).ToList();
 | 
			
		||||
 | 
			
		||||
            if (matchesScopes == null || matchesScopes.Count == 0)
 | 
			
		||||
            {
 | 
			
		||||
                return new ErrorResponse<bool>(new List<Error>
 | 
			
		||||
                {
 | 
			
		||||
                     new ScopeNotAuthorisedError(
 | 
			
		||||
                         $"no one user scope: '{string.Join(",", userScopes)}' match with some allowed scope: '{string.Join(",", routeAllowedScopes)}'")
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<bool>(true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<HttpMethod> _upstreamHttpMethod;
 | 
			
		||||
        private bool _isAuthenticated;
 | 
			
		||||
        private List<ClaimToThing> _configHeaderExtractorProperties;
 | 
			
		||||
        private List<ClaimToThing> _claimToClaims;
 | 
			
		||||
@@ -66,11 +67,13 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
            _upstreamTemplatePattern = input;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
        public ReRouteBuilder WithUpstreamHttpMethod(string input)
 | 
			
		||||
 | 
			
		||||
        public ReRouteBuilder WithUpstreamHttpMethod(List<string> input)
 | 
			
		||||
        {
 | 
			
		||||
            _upstreamHttpMethod = input;
 | 
			
		||||
            _upstreamHttpMethod = (input.Count == 0) ? new List<HttpMethod>() : input.Select(x => new HttpMethod(x.Trim())).ToList();
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ReRouteBuilder WithIsAuthenticated(bool input)
 | 
			
		||||
        {
 | 
			
		||||
            _isAuthenticated = input;
 | 
			
		||||
@@ -143,7 +146,6 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
       
 | 
			
		||||
 | 
			
		||||
        public ReRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancerKey = loadBalancerKey;
 | 
			
		||||
@@ -180,7 +182,7 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
            return new ReRoute(
 | 
			
		||||
                new PathTemplate(_downstreamPathTemplate), 
 | 
			
		||||
                new PathTemplate(_upstreamTemplate), 
 | 
			
		||||
                new HttpMethod(_upstreamHttpMethod), 
 | 
			
		||||
                _upstreamHttpMethod, 
 | 
			
		||||
                _upstreamTemplatePattern, 
 | 
			
		||||
                _isAuthenticated, 
 | 
			
		||||
                _authenticationOptions,
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Register as singleton
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class FileOcelotConfigurationCreator : IOcelotConfigurationCreator
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOptions<FileConfiguration> _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<FileConfiguration> 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
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Register as singleton
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class FileOcelotConfigurationCreator : IOcelotConfigurationCreator
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOptions<FileConfiguration> _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<FileConfiguration> 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<FileOcelotConfigurationCreator>();
 | 
			
		||||
            _claimsToThingCreator = claimsToThingCreator;
 | 
			
		||||
            _serviceProviderConfigCreator = serviceProviderConfigCreator;
 | 
			
		||||
            _qosOptionsCreator = qosOptionsCreator;
 | 
			
		||||
            _fileReRouteOptionsCreator = fileReRouteOptionsCreator;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<IOcelotConfiguration>> Create()
 | 
			
		||||
        {     
 | 
			
		||||
            var config = await SetUpConfiguration(_options.Value);
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<IOcelotConfiguration>(config);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<IOcelotConfiguration>> Create(FileConfiguration fileConfiguration)
 | 
			
		||||
        {     
 | 
			
		||||
            var config = await SetUpConfiguration(fileConfiguration);
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<IOcelotConfiguration>(config);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<IOcelotConfiguration> 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<ReRoute>();
 | 
			
		||||
 | 
			
		||||
            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<ReRoute> 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<FileOcelotConfigurationCreator>();
 | 
			
		||||
            _claimsToThingCreator = claimsToThingCreator;
 | 
			
		||||
            _serviceProviderConfigCreator = serviceProviderConfigCreator;
 | 
			
		||||
            _qosOptionsCreator = qosOptionsCreator;
 | 
			
		||||
            _fileReRouteOptionsCreator = fileReRouteOptionsCreator;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<IOcelotConfiguration>> Create()
 | 
			
		||||
        {     
 | 
			
		||||
            var config = await SetUpConfiguration(_options.Value);
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<IOcelotConfiguration>(config);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<IOcelotConfiguration>> Create(FileConfiguration fileConfiguration)
 | 
			
		||||
        {     
 | 
			
		||||
            var config = await SetUpConfiguration(fileConfiguration);
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<IOcelotConfiguration>(config);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<IOcelotConfiguration> 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<ReRoute>();
 | 
			
		||||
 | 
			
		||||
            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<ReRoute> 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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,6 +6,7 @@ namespace Ocelot.Configuration.File
 | 
			
		||||
    {
 | 
			
		||||
        public FileReRoute()
 | 
			
		||||
        {
 | 
			
		||||
            UpstreamHttpMethod = new List<string>();
 | 
			
		||||
            AddHeadersToRequest = new Dictionary<string, string>();
 | 
			
		||||
            AddClaimsToRequest = new Dictionary<string, string>();
 | 
			
		||||
            RouteClaimsRequirement = new Dictionary<string, string>();
 | 
			
		||||
@@ -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<string> UpstreamHttpMethod { get; set; }
 | 
			
		||||
        public FileAuthenticationOptions AuthenticationOptions { get; set; }
 | 
			
		||||
        public Dictionary<string, string> AddHeadersToRequest { get; set; }
 | 
			
		||||
        public Dictionary<string, string> AddClaimsToRequest { get; set; }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ namespace Ocelot.Configuration
 | 
			
		||||
    {
 | 
			
		||||
        public ReRoute(PathTemplate downstreamPathTemplate, 
 | 
			
		||||
            PathTemplate upstreamPathTemplate, 
 | 
			
		||||
            HttpMethod upstreamHttpMethod, 
 | 
			
		||||
            List<HttpMethod> 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<HttpMethod> UpstreamHttpMethod { get; private set; }
 | 
			
		||||
        public bool IsAuthenticated { get; private set; }
 | 
			
		||||
        public bool IsAuthorised { get; private set; }
 | 
			
		||||
        public AuthenticationOptions AuthenticationOptions { get; private set; }
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ namespace Ocelot.Configuration.Validator
 | 
			
		||||
    {
 | 
			
		||||
        public Response<ConfigurationValidationResult> IsValid(FileConfiguration configuration)
 | 
			
		||||
        {
 | 
			
		||||
            var result = CheckForDupliateReRoutes(configuration);
 | 
			
		||||
            var result = CheckForDuplicateReRoutes(configuration);
 | 
			
		||||
 | 
			
		||||
            if (result.IsError)
 | 
			
		||||
            {
 | 
			
		||||
@@ -97,25 +97,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<string>();
 | 
			
		||||
 | 
			
		||||
            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<Error>()
 | 
			
		||||
                    .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<Error>()
 | 
			
		||||
                .ToList();
 | 
			
		||||
 | 
			
		||||
            return new ConfigurationValidationResult(true, errors);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private ConfigurationValidationResult CheckForReRoutesRateLimitOptions(FileConfiguration configuration)
 | 
			
		||||
 
 | 
			
		||||
@@ -144,7 +144,8 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
            services.TryAddSingleton<IRemoveOutputHeaders, RemoveOutputHeaders>();
 | 
			
		||||
            services.TryAddSingleton<IOcelotConfigurationProvider, OcelotConfigurationProvider>();
 | 
			
		||||
            services.TryAddSingleton<IClaimToThingConfigurationParser, ClaimToThingConfigurationParser>();
 | 
			
		||||
            services.TryAddSingleton<IAuthoriser, ClaimsAuthoriser>();
 | 
			
		||||
            services.TryAddSingleton<IClaimsAuthoriser, ClaimsAuthoriser>();
 | 
			
		||||
            services.TryAddSingleton<IScopesAuthoriser, ScopesAuthoriser>();
 | 
			
		||||
            services.TryAddSingleton<IAddClaimsToRequest, AddClaimsToRequest>();
 | 
			
		||||
            services.TryAddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
 | 
			
		||||
            services.TryAddSingleton<IAddQueriesToRequest, AddQueriesToRequest>();
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
        InstructionNotForClaimsError,
 | 
			
		||||
        UnauthorizedError,
 | 
			
		||||
        ClaimValueNotAuthorisedError,
 | 
			
		||||
        ScopeNotAuthorisedError,
 | 
			
		||||
        UserDoesNotHaveClaimError,
 | 
			
		||||
        DownstreamPathTemplateContainsSchemeError,
 | 
			
		||||
        DownstreamPathNullOrEmptyError,
 | 
			
		||||
 
 | 
			
		||||
@@ -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<string>(value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public Response<List<string>> GetValuesByClaimType(IEnumerable<Claim> claims, string claimType)
 | 
			
		||||
        {
 | 
			
		||||
            List<string> values = new List<string>();
 | 
			
		||||
 | 
			
		||||
            values.AddRange(claims.Where(x => x.Type == claimType).Select(x => x.Value).ToList());
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<List<string>>(values);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        private Response<string> GetValue(IEnumerable<Claim> claims, string key)
 | 
			
		||||
        {
 | 
			
		||||
            var claim = claims.FirstOrDefault(c => c.Type == key);
 | 
			
		||||
 
 | 
			
		||||
@@ -7,5 +7,6 @@
 | 
			
		||||
    public interface IClaimsParser
 | 
			
		||||
    {
 | 
			
		||||
        Response<string> GetValue(IEnumerable<Claim> claims, string key, string delimiter, int index);
 | 
			
		||||
        Response<List<string>> GetValuesByClaimType(IEnumerable<Claim> claims, string claimType);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -45,7 +45,7 @@
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Authentication.Twitter" Version="1.1.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="1.1.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Authentication" Version="1.1.1" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="1.0.2" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="1.2.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
 | 
			
		||||
    <PackageReference Include="CacheManager.Core" Version="0.9.2" />
 | 
			
		||||
@@ -53,7 +53,7 @@
 | 
			
		||||
    <PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="0.9.2" />
 | 
			
		||||
    <PackageReference Include="Consul" Version="0.7.2.1" />
 | 
			
		||||
    <PackageReference Include="Polly" Version="5.0.3" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4" Version="1.0.1" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4" Version="1.5.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="1.1.1" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,9 +22,12 @@ namespace Ocelot.Requester
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<HttpResponseMessage>> 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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -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))
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -48,21 +48,21 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = _downstreamServiceHost,
 | 
			
		||||
                            DownstreamScheme = _downstreamServiceScheme,
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Post",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Post" },
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
								AllowedScopes =  new List<string>(),
 | 
			
		||||
                                AllowedScopes =  new List<string>(),
 | 
			
		||||
                                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())
 | 
			
		||||
@@ -86,21 +86,21 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = _downstreamServiceHost,
 | 
			
		||||
                            DownstreamScheme = _downstreamServiceScheme,
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Post",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Post" },
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
								AllowedScopes =  new List<string>(),
 | 
			
		||||
                                AllowedScopes =  new List<string>(),
 | 
			
		||||
                                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())
 | 
			
		||||
@@ -124,21 +124,21 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = _downstreamServiceHost,
 | 
			
		||||
                            DownstreamScheme = _downstreamServiceScheme,
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
								AllowedScopes =  new List<string>(),
 | 
			
		||||
                                AllowedScopes =  new List<string>(),
 | 
			
		||||
                                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,45 @@ 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<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = _downstreamServicePath,
 | 
			
		||||
                            DownstreamPort = _downstreamServicePort,
 | 
			
		||||
                            DownstreamHost = _downstreamServiceHost,
 | 
			
		||||
                            DownstreamScheme = _downstreamServiceScheme,
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                AllowedScopes =  new List<string>(),
 | 
			
		||||
                                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_201_using_identity_server_access_token()
 | 
			
		||||
        {
 | 
			
		||||
@@ -164,22 +203,22 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = _downstreamServiceHost,
 | 
			
		||||
                            DownstreamScheme = _downstreamServiceScheme,
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Post",
 | 
			
		||||
                            
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Post" },
 | 
			
		||||
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
								AllowedScopes =  new List<string>(),
 | 
			
		||||
                                AllowedScopes =  new List<string>(),
 | 
			
		||||
                                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))
 | 
			
		||||
@@ -205,21 +244,21 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = _downstreamServiceHost,
 | 
			
		||||
                            DownstreamScheme = _downstreamServiceScheme,
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Post",
 | 
			
		||||
                             AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Post" },
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
								AllowedScopes = new List<string>(),
 | 
			
		||||
                                AllowedScopes = new List<string>(),
 | 
			
		||||
                                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 +291,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 +315,32 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                Scopes = new List<Scope>()
 | 
			
		||||
                                {
 | 
			
		||||
                                    new Scope("api"),
 | 
			
		||||
                                    new Scope("api.readOnly"),
 | 
			
		||||
                                    new Scope("openid"),
 | 
			
		||||
                                    new Scope("offline_access")
 | 
			
		||||
                                },
 | 
			
		||||
                                ApiSecrets = new List<Secret>()
 | 
			
		||||
                                {
 | 
			
		||||
                                    new Secret
 | 
			
		||||
                                    {
 | 
			
		||||
                                        Value = "secret".Sha256()
 | 
			
		||||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                                UserClaims = new List<string>()
 | 
			
		||||
                                {
 | 
			
		||||
                                    "CustomerId", "LocationId"
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            new ApiResource
 | 
			
		||||
                            {
 | 
			
		||||
                                Name = api2Name,
 | 
			
		||||
                                Description = "My second API",
 | 
			
		||||
                                Enabled = true,
 | 
			
		||||
                                DisplayName = "second test",
 | 
			
		||||
                                Scopes = new List<Scope>()
 | 
			
		||||
                                {
 | 
			
		||||
                                    new Scope("api2"),
 | 
			
		||||
                                    new Scope("api2.readOnly"),
 | 
			
		||||
                                    new Scope("openid"),
 | 
			
		||||
                                    new Scope("offline_access")
 | 
			
		||||
                                },
 | 
			
		||||
@@ -299,7 +364,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                ClientId = "client",
 | 
			
		||||
                                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
 | 
			
		||||
                                ClientSecrets = new List<Secret> {new Secret("secret".Sha256())},
 | 
			
		||||
                                AllowedScopes = new List<string> { apiName, "openid", "offline_access" },
 | 
			
		||||
                                AllowedScopes = new List<string> { apiName, api2Name, "api.readOnly", "openid", "offline_access" },
 | 
			
		||||
                                AccessTokenType = tokenType,
 | 
			
		||||
                                Enabled = true,
 | 
			
		||||
                                RequireClientSecret = false
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
								AllowedScopes =  new List<string>(),
 | 
			
		||||
@@ -99,7 +99,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
								AllowedScopes =  new List<string>(),
 | 
			
		||||
@@ -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<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamPort = 51876,
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                AllowedScopes =  new List<string>{ "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<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamPort = 51876,
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                AllowedScopes =  new List<string>{ "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<Scope>()
 | 
			
		||||
                                {
 | 
			
		||||
                                    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<Secret> {new Secret("secret".Sha256())},
 | 
			
		||||
                                AllowedScopes = new List<string> { apiName, "openid", "offline_access" },
 | 
			
		||||
                                AllowedScopes = new List<string> { apiName, "api.readOnly", "openid", "offline_access" },
 | 
			
		||||
                                AccessTokenType = tokenType,
 | 
			
		||||
                                Enabled = true,
 | 
			
		||||
                                RequireClientSecret = false
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
@@ -72,7 +72,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 1
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -62,7 +62,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            ReRouteIsCaseSensitive = false,
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
@@ -90,7 +90,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            ReRouteIsCaseSensitive = true,
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
@@ -118,7 +118,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/PRODUCTS/{productId}",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            ReRouteIsCaseSensitive = true,
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
@@ -146,7 +146,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            ReRouteIsCaseSensitive = true,
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
@@ -174,7 +174,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/PRODUCTS/{productId}",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            ReRouteIsCaseSensitive = true,
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
@@ -56,12 +56,12 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
								AllowedScopes = new List<string>
 | 
			
		||||
                                {
 | 
			
		||||
                                    "openid", "offline_access"
 | 
			
		||||
                                    "openid", "offline_access", "api"
 | 
			
		||||
                                },
 | 
			
		||||
                                Provider = "IdentityServer",
 | 
			
		||||
                                ProviderRootUrl = "http://localhost:52888",
 | 
			
		||||
 
 | 
			
		||||
@@ -56,12 +56,12 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
								AllowedScopes = new List<string>
 | 
			
		||||
                                {
 | 
			
		||||
                                    "openid", "offline_access"
 | 
			
		||||
                                    "openid", "offline_access", "api"
 | 
			
		||||
                                },
 | 
			
		||||
                                Provider = "IdentityServer",
 | 
			
		||||
                                ProviderRootUrl = "http://localhost:57888",
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/api/ClientRateLimit",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "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<string> { "Get" },
 | 
			
		||||
                            RequestIdKey = _steps.RequestIdKey,
 | 
			
		||||
 | 
			
		||||
                            RateLimitOptions =    new FileRateLimitRule()
 | 
			
		||||
 
 | 
			
		||||
@@ -44,8 +44,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamPort = 51779,
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                GlobalConfiguration = new FileGlobalConfiguration()
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -87,8 +87,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -125,8 +124,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -163,7 +161,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -200,7 +198,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -237,7 +235,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,6 @@
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Http" Version="1.1.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="1.1.1" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4" Version="1.0.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="1.1.1" />
 | 
			
		||||
 
 | 
			
		||||
@@ -39,13 +39,14 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                        DownstreamHost = "localhost",
 | 
			
		||||
                        DownstreamPort = 51879,
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = "Get",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        QoSOptions = new FileQoSOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            ExceptionsAllowedBeforeBreaking = 1,
 | 
			
		||||
                            TimeoutValue = 500,
 | 
			
		||||
                            DurationOfBreak = 1000
 | 
			
		||||
                        }
 | 
			
		||||
                        },
 | 
			
		||||
                        
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
@@ -83,7 +84,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                        DownstreamHost = "localhost",
 | 
			
		||||
                        DownstreamPort = 51879,
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = "Get",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        QoSOptions = new FileQoSOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            ExceptionsAllowedBeforeBreaking = 1,
 | 
			
		||||
@@ -98,7 +99,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                        DownstreamHost = "localhost",
 | 
			
		||||
                        DownstreamPort = 51880,
 | 
			
		||||
                        UpstreamPathTemplate = "working",
 | 
			
		||||
                        UpstreamHttpMethod = "Get",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            RequestIdKey = _steps.RequestIdKey,
 | 
			
		||||
                         }
 | 
			
		||||
                    }
 | 
			
		||||
@@ -66,8 +66,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
 
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -96,7 +95,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                GlobalConfiguration = new FileGlobalConfiguration
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            DownstreamPort = 53876,
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost"
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamPort = 51879,
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -73,8 +73,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamPort = 51879,
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
 
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -102,8 +101,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = "localhost/",
 | 
			
		||||
                            DownstreamPort = 51879,
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
 
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -131,8 +129,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamPort = 51879,
 | 
			
		||||
                            UpstreamPathTemplate = "/products/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
 
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -160,7 +157,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamPort = 51879,
 | 
			
		||||
                            UpstreamPathTemplate = "/products",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -188,7 +185,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                        DownstreamHost = "localhost",
 | 
			
		||||
                        DownstreamPort = 51879,
 | 
			
		||||
                        UpstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
                        UpstreamHttpMethod = "Get",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "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<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -249,7 +246,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamPort = 51879,
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Post", 
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Post" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -277,7 +274,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamPort = 51879,
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -305,7 +302,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamPort = 51879,
 | 
			
		||||
                            UpstreamPathTemplate = "/myApp1Name/api/{urlPath}",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -319,6 +316,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<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamPort = 51879,
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "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<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamPort = 51879,
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string>(),
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            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()
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            ServiceName = serviceName,
 | 
			
		||||
                            LoadBalancer = "LeastConnection",
 | 
			
		||||
                        }
 | 
			
		||||
 
 | 
			
		||||
@@ -199,6 +199,52 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenIHaveATokenForApiReadOnlyScope(string url)
 | 
			
		||||
        {
 | 
			
		||||
            var tokenUrl = $"{url}/connect/token";
 | 
			
		||||
            var formData = new List<KeyValuePair<string, string>>
 | 
			
		||||
            {
 | 
			
		||||
                new KeyValuePair<string, string>("client_id", "client"),
 | 
			
		||||
                new KeyValuePair<string, string>("client_secret", "secret"),
 | 
			
		||||
                new KeyValuePair<string, string>("scope", "api.readOnly"),
 | 
			
		||||
                new KeyValuePair<string, string>("username", "test"),
 | 
			
		||||
                new KeyValuePair<string, string>("password", "test"),
 | 
			
		||||
                new KeyValuePair<string, string>("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<BearerToken>(responseContent);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenIHaveATokenForApi2(string url)
 | 
			
		||||
        {
 | 
			
		||||
            var tokenUrl = $"{url}/connect/token";
 | 
			
		||||
            var formData = new List<KeyValuePair<string, string>>
 | 
			
		||||
            {
 | 
			
		||||
                new KeyValuePair<string, string>("client_id", "client"),
 | 
			
		||||
                new KeyValuePair<string, string>("client_secret", "secret"),
 | 
			
		||||
                new KeyValuePair<string, string>("scope", "api2"),
 | 
			
		||||
                new KeyValuePair<string, string>("username", "test"),
 | 
			
		||||
                new KeyValuePair<string, string>("password", "test"),
 | 
			
		||||
                new KeyValuePair<string, string>("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<BearerToken>(responseContent);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenIHaveAnOcelotToken(string adminPath)
 | 
			
		||||
        {
 | 
			
		||||
            var tokenUrl = $"{adminPath}/connect/token";
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,7 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                        DownstreamPort = 80,
 | 
			
		||||
                        DownstreamScheme = "https",
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = "get",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "get" },
 | 
			
		||||
                        UpstreamPathTemplate = "/"
 | 
			
		||||
                    },
 | 
			
		||||
                    new FileReRoute()
 | 
			
		||||
@@ -103,7 +103,7 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                        DownstreamPort = 80,
 | 
			
		||||
                        DownstreamScheme = "https",
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = "get",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "get" },
 | 
			
		||||
                        UpstreamPathTemplate = "/test"
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@@ -136,7 +136,7 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                        DownstreamPort = 80,
 | 
			
		||||
                        DownstreamScheme = "https",
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = "get",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "get" },
 | 
			
		||||
                        UpstreamPathTemplate = "/"
 | 
			
		||||
                    },
 | 
			
		||||
                    new FileReRoute()
 | 
			
		||||
@@ -145,7 +145,7 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                        DownstreamPort = 80,
 | 
			
		||||
                        DownstreamScheme = "https",
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = "get",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "get" },
 | 
			
		||||
                        UpstreamPathTemplate = "/test"
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@@ -165,7 +165,7 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                        DownstreamPort = 80,
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamPathTemplate = "/geoffrey",
 | 
			
		||||
                        UpstreamHttpMethod = "get",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "get" },
 | 
			
		||||
                        UpstreamPathTemplate = "/"
 | 
			
		||||
                    },
 | 
			
		||||
                    new FileReRoute()
 | 
			
		||||
@@ -174,7 +174,7 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                        DownstreamPort = 443,
 | 
			
		||||
                        DownstreamScheme = "https",
 | 
			
		||||
                        DownstreamPathTemplate = "/blooper/{productId}",
 | 
			
		||||
                        UpstreamHttpMethod = "post",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "post" },
 | 
			
		||||
                        UpstreamPathTemplate = "/test"
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@
 | 
			
		||||
    <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" />
 | 
			
		||||
    <PackageReference Include="xunit" Version="2.3.0-beta2-build3683" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="1.1.1" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4" Version="1.0.1" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4" Version="1.5.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
 | 
			
		||||
    <PackageReference Include="Shouldly" Version="2.8.2" />
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamPort = 51879,
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = "Get",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 
 | 
			
		||||
@@ -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",
 | 
			
		||||
 
 | 
			
		||||
@@ -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<UrlPathPlaceholderNameAndValue>(), new ReRouteBuilder()
 | 
			
		||||
                                                                                                                            .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                                                                                                                            .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                                                                                                                            .Build())))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheUserIsAuthenticated())
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,8 @@ namespace Ocelot.UnitTests.Authorization
 | 
			
		||||
    public class AuthorisationMiddlewareTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IRequestScopedDataRepository> _scopedRepository;
 | 
			
		||||
        private readonly Mock<IAuthoriser> _authService;
 | 
			
		||||
        private readonly Mock<IClaimsAuthoriser> _authService;
 | 
			
		||||
        private readonly Mock<IScopesAuthoriser> _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<IRequestScopedDataRepository>();
 | 
			
		||||
            _authService = new Mock<IAuthoriser>();
 | 
			
		||||
            _authService = new Mock<IClaimsAuthoriser>();
 | 
			
		||||
            _authScopesService = new Mock<IScopesAuthoriser>();
 | 
			
		||||
 | 
			
		||||
            var builder = new WebHostBuilder()
 | 
			
		||||
              .ConfigureServices(x =>
 | 
			
		||||
@@ -44,6 +46,7 @@ namespace Ocelot.UnitTests.Authorization
 | 
			
		||||
                  x.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
			
		||||
                  x.AddLogging();
 | 
			
		||||
                  x.AddSingleton(_authService.Object);
 | 
			
		||||
                  x.AddSingleton(_authScopesService.Object);
 | 
			
		||||
                  x.AddSingleton(_scopedRepository.Object);
 | 
			
		||||
              })
 | 
			
		||||
              .UseUrls(_url)
 | 
			
		||||
@@ -66,7 +69,7 @@ namespace Ocelot.UnitTests.Authorization
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), 
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithIsAuthorised(true)
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")                                                                                                                                                                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build())))
 | 
			
		||||
                .And(x => x.GivenTheAuthServiceReturns(new OkResponse<bool>(true)))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
 
 | 
			
		||||
@@ -91,7 +91,7 @@ namespace Ocelot.UnitTests.Cache
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithIsCached(true)
 | 
			
		||||
                .WithCacheOptions(new CacheOptions(100))
 | 
			
		||||
                .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .Build();
 | 
			
		||||
                
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), reRoute);
 | 
			
		||||
 
 | 
			
		||||
@@ -72,7 +72,7 @@ namespace Ocelot.UnitTests.Claims
 | 
			
		||||
                    {
 | 
			
		||||
                        new ClaimToThing("sub", "UserType", "|", 0)
 | 
			
		||||
                    })
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
 
 | 
			
		||||
@@ -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<string> { "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<string> { "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<string> { "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<string> { "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<string> { "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<string> { "Get" },
 | 
			
		||||
                                                }
 | 
			
		||||
                                            },
 | 
			
		||||
                                        }))
 | 
			
		||||
@@ -228,7 +228,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                                                    .WithDownstreamScheme("https")
 | 
			
		||||
                                                    .WithDownstreamPathTemplate("/products/{productId}")
 | 
			
		||||
                                                    .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
			
		||||
                                                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                                                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                                                    .Build()
 | 
			
		||||
                                            }))
 | 
			
		||||
                                .BDDfy();
 | 
			
		||||
@@ -248,7 +248,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                                {
 | 
			
		||||
                                    UpstreamPathTemplate = "/api/products/{productId}",
 | 
			
		||||
                                    DownstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
                                    UpstreamHttpMethod = "Get",
 | 
			
		||||
                                    UpstreamHttpMethod = new List<string> { "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<string> { "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<string> { "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<string> { "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<string> { "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<string> { "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<string> { "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<string> { "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<string> { "Get" })
 | 
			
		||||
                    .WithAuthenticationOptions(authenticationOptions)
 | 
			
		||||
                    .WithClaimsToHeaders(new List<ClaimToThing>
 | 
			
		||||
                    {
 | 
			
		||||
@@ -431,7 +431,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                    {
 | 
			
		||||
                        UpstreamPathTemplate = "/api/products/{productId}",
 | 
			
		||||
                        DownstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
                        UpstreamHttpMethod = "Get",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "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<string> { "Get" })
 | 
			
		||||
                    .WithAuthenticationOptions(authenticationOptions)
 | 
			
		||||
                    .Build()
 | 
			
		||||
            };
 | 
			
		||||
@@ -495,7 +495,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                    {
 | 
			
		||||
                        UpstreamPathTemplate = "/api/products/{productId}",
 | 
			
		||||
                        DownstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
                        UpstreamHttpMethod = "Get",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        ReRouteIsCaseSensitive = true,
 | 
			
		||||
                        AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                            {
 | 
			
		||||
 
 | 
			
		||||
@@ -87,7 +87,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            {
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate(_downstreamTemplatePath)
 | 
			
		||||
                .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .Build()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                    new List<UrlPathPlaceholderNameAndValue>(), 
 | 
			
		||||
                    new ReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                    new ReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("someDownstreamPath")
 | 
			
		||||
                        .WithUpstreamPathTemplate("someUpstreamPath")
 | 
			
		||||
                        .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("someUpstreamPath")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
@@ -58,7 +58,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                            new List<UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                            new ReRouteBuilder()
 | 
			
		||||
                                .WithDownstreamPathTemplate("someDownstreamPath")
 | 
			
		||||
                                .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                                .WithUpstreamHttpMethod(new List<string> { "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<string> { "Get" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("someUpstreamPath")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
@@ -90,7 +90,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                    x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamPathTemplate("someDownstreamPath")
 | 
			
		||||
                            .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "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<string> { "Get" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("")
 | 
			
		||||
                        .Build(),
 | 
			
		||||
                    new ReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("someDownstreamPathForAPost")
 | 
			
		||||
                        .WithUpstreamPathTemplate("someUpstreamPath")
 | 
			
		||||
                        .WithUpstreamHttpMethod("Post")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Post" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
@@ -128,7 +128,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                    x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamPathTemplate("someDownstreamPathForAPost")
 | 
			
		||||
                            .WithUpstreamHttpMethod("Post")
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "Post" })
 | 
			
		||||
                            .Build()
 | 
			
		||||
                        )))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
@@ -143,7 +143,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("somPath")
 | 
			
		||||
                        .WithUpstreamPathTemplate("somePath")
 | 
			
		||||
                        .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("somePath")
 | 
			
		||||
                        .Build(),   
 | 
			
		||||
                     }, string.Empty
 | 
			
		||||
@@ -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<List<UrlPathPlaceholderNameAndValue>>(new List<UrlPathPlaceholderNameAndValue>())))
 | 
			
		||||
                .And(x => x.GivenTheConfigurationIs(new List<ReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new ReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("someDownstreamPath")
 | 
			
		||||
                        .WithUpstreamPathTemplate("someUpstreamPath")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get", "Post" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
                    ))
 | 
			
		||||
                .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
 | 
			
		||||
                .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
 | 
			
		||||
                .When(x => x.WhenICallTheFinder())
 | 
			
		||||
                .Then(
 | 
			
		||||
                    x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamPathTemplate("someDownstreamPath")
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "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<List<UrlPathPlaceholderNameAndValue>>(new List<UrlPathPlaceholderNameAndValue>())))
 | 
			
		||||
                .And(x => x.GivenTheConfigurationIs(new List<ReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new ReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("someDownstreamPath")
 | 
			
		||||
                        .WithUpstreamPathTemplate("someUpstreamPath")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string>())
 | 
			
		||||
                        .WithUpstreamTemplatePattern("")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
                    ))
 | 
			
		||||
                .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
 | 
			
		||||
                .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
 | 
			
		||||
                .When(x => x.WhenICallTheFinder())
 | 
			
		||||
                .Then(
 | 
			
		||||
                    x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamPathTemplate("someDownstreamPath")
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "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<List<UrlPathPlaceholderNameAndValue>>(new List<UrlPathPlaceholderNameAndValue>())))
 | 
			
		||||
                .And(x => x.GivenTheConfigurationIs(new List<ReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new ReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("someDownstreamPath")
 | 
			
		||||
                        .WithUpstreamPathTemplate("someUpstreamPath")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
                    ))
 | 
			
		||||
                .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(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<List<UrlPathPlaceholderNameAndValue>> response)
 | 
			
		||||
        {
 | 
			
		||||
            _finder
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
 | 
			
		||||
                    new List<UrlPathPlaceholderNameAndValue>(), 
 | 
			
		||||
                    new ReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .WithDownstreamScheme("https")
 | 
			
		||||
                        .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123"))
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
 | 
			
		||||
                new DownstreamRoute(
 | 
			
		||||
                    new List<UrlPathPlaceholderNameAndValue>(), 
 | 
			
		||||
                    new ReRouteBuilder()
 | 
			
		||||
                        .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())))
 | 
			
		||||
                .When(x => x.WhenIReplaceTheTemplateVariables())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamUrlPathIsReturned(""))
 | 
			
		||||
@@ -44,7 +44,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
 | 
			
		||||
                new List<UrlPathPlaceholderNameAndValue>(), 
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamPathTemplate("/")
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "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<UrlPathPlaceholderNameAndValue>(), 
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamPathTemplate("api")
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "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<UrlPathPlaceholderNameAndValue>(), 
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamPathTemplate("api/")
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "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<UrlPathPlaceholderNameAndValue>(), 
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamPathTemplate("api/product/products/")
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "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<string> { "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<string> { "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<string> { "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<string> { "Get" })
 | 
			
		||||
                .Build())))
 | 
			
		||||
             .When(x => x.WhenIReplaceTheTemplateVariables())
 | 
			
		||||
             .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12"))
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,7 @@ namespace Ocelot.UnitTests.Headers
 | 
			
		||||
                    {
 | 
			
		||||
                        new ClaimToThing("UserId", "Subject", "", 0)
 | 
			
		||||
                    })
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
 
 | 
			
		||||
@@ -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<string> { "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<string> { "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<string> { "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<string> { "Get" })
 | 
			
		||||
                .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -73,7 +73,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "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<Ocelot.DownstreamRouteFinder.UrlMatcher.UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "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<Ocelot.DownstreamRouteFinder.UrlMatcher.UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
 | 
			
		||||
 
 | 
			
		||||
@@ -74,7 +74,7 @@ namespace Ocelot.UnitTests.QueryStrings
 | 
			
		||||
                    {
 | 
			
		||||
                        new ClaimToThing("UserId", "Subject", "", 0)
 | 
			
		||||
                    })
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
 
 | 
			
		||||
@@ -72,7 +72,7 @@ namespace Ocelot.UnitTests.RateLimit
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                 new ReRouteBuilder().WithEnableRateLimiting(true).WithRateLimitOptions(
 | 
			
		||||
                     new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List<string>(), false, "", "", new Ocelot.Configuration.RateLimitRule("1s", 100, 3), 429))
 | 
			
		||||
                     .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                     .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                     .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
@@ -89,7 +89,7 @@ namespace Ocelot.UnitTests.RateLimit
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                 new ReRouteBuilder().WithEnableRateLimiting(true).WithRateLimitOptions(
 | 
			
		||||
                     new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List<string>() { "ocelotclient2" }, false, "", "", new  RateLimitRule( "1s", 100,3),429))
 | 
			
		||||
                     .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                     .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                     .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,7 @@ namespace Ocelot.UnitTests.Request
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ namespace Ocelot.UnitTests.RequestId
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "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<string> { "Get" })
 | 
			
		||||
                .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
 
 | 
			
		||||
@@ -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<string> { "get" })
 | 
			
		||||
                .WithIsQos(false)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
@@ -51,7 +52,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
               .WithUpstreamHttpMethod("get")
 | 
			
		||||
               .WithUpstreamHttpMethod(new List<string> { "get" })
 | 
			
		||||
               .WithIsQos(true)
 | 
			
		||||
               .WithQosOptions(qosOptions)
 | 
			
		||||
               .Build();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user