#309 allow users to ignore ssl warnings, not sure this is advisable (#325)

* #309 allow users to ignore ssl warnings, not sure this is advisable

* #309 docs for ssl ignore
This commit is contained in:
Tom Pallister 2018-04-22 12:05:49 +01:00 committed by GitHub
parent 4f061f2b74
commit 636d116491
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 218 additions and 13 deletions

View File

@ -64,7 +64,8 @@ Here is an example ReRoute configuration, You don't need to set all of these thi
"UseCookieContainer": true, "UseCookieContainer": true,
"UseTracing": true "UseTracing": true
}, },
"UseServiceDiscovery": false "UseServiceDiscovery": false,
"DangerousAcceptAnyServerCertificateValidator": false
} }
More information on how to use these options is below.. More information on how to use these options is below..
@ -160,3 +161,14 @@ noticed that the cookies were being shared. I tried to think of a nice way to ha
that means each request gets a new client and therefore a new cookie container. If you clear the cookies from the cached client container you get race conditions due to inflight that means each request gets a new client and therefore a new cookie container. If you clear the cookies from the cached client container you get race conditions due to inflight
requests. This would also mean that subsequent requests dont use the cookies from the previous response! All in all not a great situation. I would avoid setting requests. This would also mean that subsequent requests dont use the cookies from the previous response! All in all not a great situation. I would avoid setting
UseCookieContainer to true unless you have a really really good reason. Just look at your response headers and forward the cookies back with your next request! UseCookieContainer to true unless you have a really really good reason. Just look at your response headers and forward the cookies back with your next request!
SSL Errors
----------
Id you want to ignore SSL warnings / errors set the following in your ReRoute config.
.. code-block:: json
"DangerousAcceptAnyServerCertificateValidator": false
I don't reccomend doing this, I suggest creating your own certificate and then getting it trusted by your local / remote machine if you can.

View File

@ -40,6 +40,7 @@ namespace Ocelot.Configuration.Builder
private List<string> _delegatingHandlers; private List<string> _delegatingHandlers;
private List<AddHeader> _addHeadersToDownstream; private List<AddHeader> _addHeadersToDownstream;
private List<AddHeader> _addHeadersToUpstream; private List<AddHeader> _addHeadersToUpstream;
private bool _dangerousAcceptAnyServerCertificateValidator;
public DownstreamReRouteBuilder() public DownstreamReRouteBuilder()
{ {
@ -241,6 +242,12 @@ namespace Ocelot.Configuration.Builder
return this; return this;
} }
public DownstreamReRouteBuilder WithDangerousAcceptAnyServerCertificateValidator(bool dangerousAcceptAnyServerCertificateValidator)
{
_dangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator;
return this;
}
public DownstreamReRoute Build() public DownstreamReRoute Build()
{ {
return new DownstreamReRoute( return new DownstreamReRoute(
@ -272,7 +279,8 @@ namespace Ocelot.Configuration.Builder
_reRouteKey, _reRouteKey,
_delegatingHandlers, _delegatingHandlers,
_addHeadersToDownstream, _addHeadersToDownstream,
_addHeadersToUpstream); _addHeadersToUpstream,
_dangerousAcceptAnyServerCertificateValidator);
} }
} }
} }

View File

@ -213,6 +213,7 @@ namespace Ocelot.Configuration.Creator
.WithDelegatingHandlers(fileReRoute.DelegatingHandlers) .WithDelegatingHandlers(fileReRoute.DelegatingHandlers)
.WithAddHeadersToDownstream(hAndRs.AddHeadersToDownstream) .WithAddHeadersToDownstream(hAndRs.AddHeadersToDownstream)
.WithAddHeadersToUpstream(hAndRs.AddHeadersToUpstream) .WithAddHeadersToUpstream(hAndRs.AddHeadersToUpstream)
.WithDangerousAcceptAnyServerCertificateValidator(fileReRoute.DangerousAcceptAnyServerCertificateValidator)
.Build(); .Build();
return reRoute; return reRoute;

View File

@ -35,8 +35,10 @@ namespace Ocelot.Configuration
string reRouteKey, string reRouteKey,
List<string> delegatingHandlers, List<string> delegatingHandlers,
List<AddHeader> addHeadersToDownstream, List<AddHeader> addHeadersToDownstream,
List<AddHeader> addHeadersToUpstream) List<AddHeader> addHeadersToUpstream,
bool dangerousAcceptAnyServerCertificateValidator)
{ {
DangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator;
AddHeadersToDownstream = addHeadersToDownstream; AddHeadersToDownstream = addHeadersToDownstream;
DelegatingHandlers = delegatingHandlers; DelegatingHandlers = delegatingHandlers;
Key = key; Key = key;
@ -97,5 +99,6 @@ namespace Ocelot.Configuration
public List<string> DelegatingHandlers {get;private set;} public List<string> DelegatingHandlers {get;private set;}
public List<AddHeader> AddHeadersToDownstream {get;private set;} public List<AddHeader> AddHeadersToDownstream {get;private set;}
public List<AddHeader> AddHeadersToUpstream { get; private set; } public List<AddHeader> AddHeadersToUpstream { get; private set; }
public bool DangerousAcceptAnyServerCertificateValidator { get; private set; }
} }
} }

View File

@ -49,5 +49,6 @@ namespace Ocelot.Configuration.File
public List<string> DelegatingHandlers {get;set;} public List<string> DelegatingHandlers {get;set;}
public int Priority { get;set; } public int Priority { get;set; }
public int Timeout { get; set; } public int Timeout { get; set; }
public bool DangerousAcceptAnyServerCertificateValidator { get; set; }
} }
} }

View File

@ -16,7 +16,6 @@ namespace Ocelot.Requester
private string _cacheKey; private string _cacheKey;
private HttpClient _httpClient; private HttpClient _httpClient;
private IHttpClient _client; private IHttpClient _client;
private HttpClientHandler _httpclientHandler;
private readonly TimeSpan _defaultTimeout; private readonly TimeSpan _defaultTimeout;
public HttpClientBuilder( public HttpClientBuilder(
@ -33,9 +32,9 @@ namespace Ocelot.Requester
_defaultTimeout = TimeSpan.FromSeconds(90); _defaultTimeout = TimeSpan.FromSeconds(90);
} }
public IHttpClient Create(DownstreamContext request) public IHttpClient Create(DownstreamContext context)
{ {
_cacheKey = GetCacheKey(request); _cacheKey = GetCacheKey(context);
var httpClient = _cacheHandlers.Get(_cacheKey); var httpClient = _cacheHandlers.Get(_cacheKey);
@ -44,18 +43,26 @@ namespace Ocelot.Requester
return httpClient; return httpClient;
} }
_httpclientHandler = new HttpClientHandler var httpclientHandler = new HttpClientHandler
{ {
AllowAutoRedirect = request.DownstreamReRoute.HttpHandlerOptions.AllowAutoRedirect, AllowAutoRedirect = context.DownstreamReRoute.HttpHandlerOptions.AllowAutoRedirect,
UseCookies = request.DownstreamReRoute.HttpHandlerOptions.UseCookieContainer, UseCookies = context.DownstreamReRoute.HttpHandlerOptions.UseCookieContainer,
CookieContainer = new CookieContainer() CookieContainer = new CookieContainer()
}; };
var timeout = request.DownstreamReRoute.QosOptionsOptions.TimeoutValue == 0 if(context.DownstreamReRoute.DangerousAcceptAnyServerCertificateValidator)
? _defaultTimeout {
: TimeSpan.FromMilliseconds(request.DownstreamReRoute.QosOptionsOptions.TimeoutValue); httpclientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
_httpClient = new HttpClient(CreateHttpMessageHandler(_httpclientHandler, request.DownstreamReRoute)) _logger
.LogWarning($"You have ignored all SSL warnings by using DangerousAcceptAnyServerCertificateValidator for this DownstreamReRoute, UpstreamPathTemplate: {context.DownstreamReRoute.UpstreamPathTemplate}, DownstreamPathTemplate: {context.DownstreamReRoute.DownstreamPathTemplate}");
}
var timeout = context.DownstreamReRoute.QosOptionsOptions.TimeoutValue == 0
? _defaultTimeout
: TimeSpan.FromMilliseconds(context.DownstreamReRoute.QosOptionsOptions.TimeoutValue);
_httpClient = new HttpClient(CreateHttpMessageHandler(httpclientHandler, context.DownstreamReRoute))
{ {
Timeout = timeout Timeout = timeout
}; };

View File

@ -21,6 +21,9 @@
<None Update="appsettings.json"> <None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="idsrv3test.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" /> <ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />

View File

@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.AcceptanceTests
{
public class SslTests : IDisposable
{
private IWebHost _builder;
private readonly Steps _steps;
private string _downstreamPath;
public SslTests()
{
_steps = new Steps();
}
[Fact]
public void should_dangerous_accept_any_server_certificate_validator()
{
int port = 51129;
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "https",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
DangerousAcceptAnyServerCertificateValidator = true
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"https://localhost:{port}", "/", 200, "Hello from Laura", port))
.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();
}
[Fact]
public void should_not_dangerous_accept_any_server_certificate_validator()
{
int port = 52129;
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "https",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
DangerousAcceptAnyServerCertificateValidator = false
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"https://localhost:{port}", "/", 200, "Hello from Laura", port))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody, int port)
{
_builder = new WebHostBuilder()
.UseUrls(baseUrl)
.UseKestrel(options =>
{
options.Listen(IPAddress.Loopback, port, listenOptions =>
{
listenOptions.UseHttps("idsrv3test.pfx", "idsrv3test");
});
})
.UseContentRoot(Directory.GetCurrentDirectory())
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
_downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if(_downstreamPath != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
})
.Build();
_builder.Start();
}
internal void ThenTheDownstreamUrlPathShouldBe(string expectedDownstreamPath)
{
_downstreamPath.ShouldBe(expectedDownstreamPath);
}
public void Dispose()
{
_builder?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -60,6 +60,25 @@ namespace Ocelot.UnitTests.Requester
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_log_if_ignoring_ssl_errors()
{
var reRoute = new DownstreamReRouteBuilder()
.WithIsQos(false)
.WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false))
.WithReRouteKey("")
.WithQosOptions(new QoSOptionsBuilder().Build())
.WithDangerousAcceptAnyServerCertificateValidator(true)
.Build();
this.Given(x => GivenTheFactoryReturns())
.And(x => GivenARequest(reRoute))
.When(x => WhenIBuild())
.Then(x => ThenTheHttpClientShouldNotBeNull())
.Then(x => ThenTheDangerousAcceptAnyServerCertificateValidatorWarningIsLogged())
.BDDfy();
}
[Fact] [Fact]
public void should_call_delegating_handlers_in_order() public void should_call_delegating_handlers_in_order()
{ {
@ -111,6 +130,11 @@ namespace Ocelot.UnitTests.Requester
.BDDfy(); .BDDfy();
} }
private void ThenTheDangerousAcceptAnyServerCertificateValidatorWarningIsLogged()
{
_logger.Verify(x => x.LogWarning($"You have ignored all SSL warnings by using DangerousAcceptAnyServerCertificateValidator for this DownstreamReRoute, UpstreamPathTemplate: {_context.DownstreamReRoute.UpstreamPathTemplate}, DownstreamPathTemplate: {_context.DownstreamReRoute.DownstreamPathTemplate}"), Times.Once);
}
private void GivenTheClientIsCached() private void GivenTheClientIsCached()
{ {
_cacheHandlers.Setup(x => x.Get(It.IsAny<string>())).Returns(_httpClient); _cacheHandlers.Setup(x => x.Get(It.IsAny<string>())).Returns(_httpClient);