Expose the SslServerAuthenticationOptions via a callback #9349 (#10310)

This commit is contained in:
Chris Ross 2019-05-17 13:05:45 -07:00 committed by GitHub
parent 818dc3b74a
commit 8b99354419
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 85 additions and 6 deletions

View File

@ -301,6 +301,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
public Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode ClientCertificateMode { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.Func<System.Security.Cryptography.X509Certificates.X509Certificate2, System.Security.Cryptography.X509Certificates.X509Chain, System.Net.Security.SslPolicyErrors, bool> ClientCertificateValidation { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.TimeSpan HandshakeTimeout { get { throw null; } set { } }
public System.Action<Microsoft.AspNetCore.Connections.ConnectionContext, System.Net.Security.SslServerAuthenticationOptions> OnAuthenticate { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.Security.Cryptography.X509Certificates.X509Certificate2 ServerCertificate { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.Func<Microsoft.AspNetCore.Connections.ConnectionContext, string, System.Security.Cryptography.X509Certificates.X509Certificate2> ServerCertificateSelector { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.Security.Authentication.SslProtocols SslProtocols { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }

View File

@ -75,6 +75,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
/// </summary>
public bool CheckCertificateRevocation { get; set; }
/// <summary>
/// Provides direct configuration of the <see cref="SslServerAuthenticationOptions"/> on a per-connection basis.
/// This is called after all of the other settings have already been applied.
/// </summary>
public Action<ConnectionContext, SslServerAuthenticationOptions> OnAuthenticate { get; set; }
/// <summary>
/// Specifies the maximum amount of time allowed for the TLS/SSL handshake. This must be positive and finite.
/// </summary>
@ -90,8 +96,5 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https
_handshakeTimeout = value != Timeout.InfiniteTimeSpan ? value : TimeSpan.MaxValue;
}
}
// For testing
internal Action OnHandshakeStarted;
}
}

View File

@ -127,8 +127,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https.Internal
var timeoutFeature = context.Features.Get<IConnectionTimeoutFeature>();
timeoutFeature.SetTimeout(_options.HandshakeTimeout);
_options.OnHandshakeStarted?.Invoke();
try
{
// Adapt to the SslStream signature
@ -170,6 +168,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https.Internal
sslOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http11);
}
_options.OnAuthenticate?.Invoke(context.ConnectionContext, sslOptions);
await sslStream.AuthenticateAsServerAsync(sslOptions, CancellationToken.None);
}
catch (OperationCanceledException)

View File

@ -326,7 +326,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
listenOptions.UseHttps(o =>
{
o.ServerCertificate = new X509Certificate2(TestResources.GetTestCertificate());
o.OnHandshakeStarted = () => handshakeStartedTcs.SetResult(null);
o.OnAuthenticate = (_, __) => handshakeStartedTcs.SetResult(null);
handshakeTimeout = o.HandshakeTimeout;
});
@ -380,6 +380,81 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
Assert.Equal(LogLevel.Debug, loggerProvider.FilterLogger.LastLogLevel);
}
[Fact]
public async Task OnAuthenticate_SeesOtherSettings()
{
var loggerProvider = new HandshakeErrorLoggerProvider();
LoggerFactory.AddProvider(loggerProvider);
var testCert = TestResources.GetTestCertificate();
var onAuthenticateCalled = false;
await using (var server = new TestServer(context => Task.CompletedTask,
new TestServiceContext(LoggerFactory),
listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
httpsOptions.ServerCertificate = testCert;
httpsOptions.OnAuthenticate = (connectionContext, authOptions) =>
{
Assert.Same(testCert, authOptions.ServerCertificate);
onAuthenticateCalled = true;
};
});
}))
{
using (var connection = server.CreateConnection())
using (var sslStream = new SslStream(connection.Stream, true, (sender, certificate, chain, errors) => true))
{
await sslStream.AuthenticateAsClientAsync("127.0.0.1", clientCertificates: null,
enabledSslProtocols: SslProtocols.None,
checkCertificateRevocation: false);
}
}
Assert.True(onAuthenticateCalled, "onAuthenticateCalled");
}
[Fact]
public async Task OnAuthenticate_CanSetSettings()
{
var loggerProvider = new HandshakeErrorLoggerProvider();
LoggerFactory.AddProvider(loggerProvider);
var testCert = TestResources.GetTestCertificate();
var onAuthenticateCalled = false;
await using (var server = new TestServer(context => Task.CompletedTask,
new TestServiceContext(LoggerFactory),
listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
httpsOptions.ServerCertificateSelector = (_, __) => throw new NotImplementedException();
httpsOptions.OnAuthenticate = (connectionContext, authOptions) =>
{
Assert.Null(authOptions.ServerCertificate);
Assert.NotNull(authOptions.ServerCertificateSelectionCallback);
authOptions.ServerCertificate = testCert;
authOptions.ServerCertificateSelectionCallback = null;
onAuthenticateCalled = true;
};
});
}))
{
using (var connection = server.CreateConnection())
using (var sslStream = new SslStream(connection.Stream, true, (sender, certificate, chain, errors) => true))
{
await sslStream.AuthenticateAsClientAsync("127.0.0.1", clientCertificates: null,
enabledSslProtocols: SslProtocols.None,
checkCertificateRevocation: false);
}
}
Assert.True(onAuthenticateCalled, "onAuthenticateCalled");
}
private class HandshakeErrorLoggerProvider : ILoggerProvider
{
public HttpsConnectionFilterLogger FilterLogger { get; } = new HttpsConnectionFilterLogger();