Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tls Handshake Layout Render #802

Merged
merged 6 commits into from
Jul 3, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using NLog.LayoutRenderers;
using NLog.Web.Internal;
using System.Text;

namespace NLog.Web.LayoutRenderers
{
/// <summary>
/// ASP.NET TSL Handshake
/// </summary>
/// <remarks>
/// ${aspnet-tls-handshake}
/// </remarks>
[LayoutRenderer("aspnet-tls-handshake")]
public class AspNetTlsHandshakeLayoutRenderer : AspNetLayoutRendererBase
{
/// <summary>
/// Specifies which of the 7 properties of ITlsHandshakeFeature to emit
/// Defaults to the protocol
/// </summary>
public TlsHandshakeProperty Property { get; set; } = TlsHandshakeProperty.Protocol;
snakefoot marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Render TLS Handshake Cipher Algorithm
/// </summary>
/// <param name="builder"></param>
/// <param name="logEvent"></param>
protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
{
#if ASP_NET_CORE3
var tlsHandshake = HttpContextAccessor.HttpContext.TryGetTlsHandshake();
if (tlsHandshake == null)
{
return;
}

switch (Property)
{
case TlsHandshakeProperty.CipherAlgorithm:
builder.Append(tlsHandshake.CipherAlgorithm);
break;
case TlsHandshakeProperty.CipherStrength:
builder.Append(tlsHandshake.CipherStrength);
break;
case TlsHandshakeProperty.HashAlgorithm:
builder.Append(tlsHandshake.HashAlgorithm);
break;
case TlsHandshakeProperty.HashStrength:
builder.Append(tlsHandshake.HashStrength);
break;
case TlsHandshakeProperty.KeyExchangeAlgorithm:
builder.Append(tlsHandshake.KeyExchangeAlgorithm);
break;
case TlsHandshakeProperty.KeyExchangeStrength:
builder.Append(tlsHandshake.KeyExchangeStrength);
break;
case TlsHandshakeProperty.Protocol:
builder.Append(tlsHandshake.Protocol);
break;
}
#endif
}
}
}
37 changes: 37 additions & 0 deletions src/NLog.Web.AspNetCore/LayoutRenderers/TlsHandshakeProperty.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace NLog.Web.LayoutRenderers
{
/// <summary>
/// Specifies which of the 7 properties of ITlsHandshakeFeature to emit
/// </summary>
public enum TlsHandshakeProperty
{
/// <summary>
/// Gets the CipherAlgorithmType.
/// </summary>
CipherAlgorithm,
/// <summary>
/// Gets the cipher strength
/// </summary>
CipherStrength,
/// <summary>
/// Gets the HashAlgorithmType.
/// </summary>
HashAlgorithm,
/// <summary>
/// Gets the hash strength.
/// </summary>
HashStrength,
/// <summary>
/// Gets the KeyExchangeAlgorithm.
/// </summary>
KeyExchangeAlgorithm,
/// <summary>
/// Gets the key exchange algorithm strength.
/// </summary>
KeyExchangeStrength,
/// <summary>
/// Gets the key exchange algorithm strength.
snakefoot marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
Protocol
}
}
33 changes: 33 additions & 0 deletions src/Shared/Internal/HttpContextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
using System.Web;
#else
using System.Text;
#if ASP_NET_CORE3
using Microsoft.AspNetCore.Connections.Features;
#endif
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
#endif
Expand Down Expand Up @@ -61,6 +64,36 @@ internal static HttpResponse TryGetResponse(this HttpContext context)
InternalLogger.Debug("HttpContext Response Lookup returned null");
return response;
}

#if ASP_NET_CORE3
internal static ITlsHandshakeFeature TryGetTlsHandshake(this HttpContext context)
{
try
{
var tlsHandshake = context?.Features.Get<ITlsHandshakeFeature>();
if (tlsHandshake != null)
{
return tlsHandshake;
}
else
{
InternalLogger.Debug("HttpContext ITlsHandshakeFeature Feature not available");
return null;
}
}
catch (ObjectDisposedException ex)
{
InternalLogger.Debug(ex, "HttpContext ITlsHandshakeFeature Disposed.");
return null; // System.ObjectDisposedException: IFeatureCollection has been disposed.
}
catch (InvalidOperationException ex)
{
InternalLogger.Debug(ex, "HttpContext ITlsHandshakeFeature Lookup failed.");
return null; // System.InvalidOperationException: ITlsHandshakeFeature has not been configured for this application or request.
}
}
#endif

#endif

#if ASP_NET_CORE2
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using NLog.Web.LayoutRenderers;
using NSubstitute;
using System.Security.Authentication;
using Xunit;

namespace NLog.Web.Tests.LayoutRenderers
{
public class AspNetTlsHandshakeLayoutRendererTests : LayoutRenderersTestBase<AspNetTlsHandshakeLayoutRenderer>
{
#if ASP_NET_CORE3

private static void SetupFeature(HttpContext httpContext)
{
var tlsHandshakeFeature = Substitute.For<ITlsHandshakeFeature>();

tlsHandshakeFeature.CipherAlgorithm.Returns(CipherAlgorithmType.Aes256);
tlsHandshakeFeature.CipherStrength.Returns(256);

tlsHandshakeFeature.HashAlgorithm.Returns(HashAlgorithmType.Sha512);
tlsHandshakeFeature.HashStrength.Returns(512);

tlsHandshakeFeature.KeyExchangeAlgorithm.Returns(ExchangeAlgorithmType.RsaSign);
tlsHandshakeFeature.KeyExchangeStrength.Returns(1024);

tlsHandshakeFeature.Protocol.Returns(SslProtocols.Tls13);


var featureCollection = new FeatureCollection();
featureCollection.Set<ITlsHandshakeFeature>(tlsHandshakeFeature);

httpContext.Features.Returns(featureCollection);
}

[Fact]
public void CipherAlgorithmTest()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();
renderer.Property = TlsHandshakeProperty.CipherAlgorithm;
SetupFeature(httpContext);
// Act
var result = renderer.Render(new LogEventInfo());
// Assert
Assert.Equal(CipherAlgorithmType.Aes256.ToString(), result);
}


[Fact]
public void CipherStrengthTest()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();
renderer.Property = TlsHandshakeProperty.CipherStrength;
SetupFeature(httpContext);
// Act
var result = renderer.Render(new LogEventInfo());
// Assert
Assert.Equal("256", result);
}

[Fact]
public void HashAlgorithmTest()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();
renderer.Property = TlsHandshakeProperty.HashAlgorithm;
SetupFeature(httpContext);
// Act
var result = renderer.Render(new LogEventInfo());
// Assert
Assert.Equal(HashAlgorithmType.Sha512.ToString(), result);
}

[Fact]
public void HashStrengthTest()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();
renderer.Property = TlsHandshakeProperty.HashStrength;
SetupFeature(httpContext);
// Act
var result = renderer.Render(new LogEventInfo());
// Assert
Assert.Equal("512", result);
}

[Fact]
public void KeyExchangeAlgorithmTest()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();
renderer.Property = TlsHandshakeProperty.KeyExchangeAlgorithm;
SetupFeature(httpContext);
// Act
var result = renderer.Render(new LogEventInfo());
// Assert
Assert.Equal(ExchangeAlgorithmType.RsaSign.ToString(), result);
}

[Fact]
public void KeyExchangeStrengthTest()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();
renderer.Property = TlsHandshakeProperty.KeyExchangeStrength;
SetupFeature(httpContext);
// Act
var result = renderer.Render(new LogEventInfo());
// Assert
Assert.Equal("1024", result);
}

[Fact]
public void ProtocolTest()
{
// Arrange
var (renderer, httpContext) = CreateWithHttpContext();
renderer.Property = TlsHandshakeProperty.Protocol;
SetupFeature(httpContext);
// Act
var result = renderer.Render(new LogEventInfo());
// Assert
Assert.Equal(SslProtocols.Tls13.ToString(), result);
}


protected override void NullRendersEmptyString()
{
// Arrange
var (renderer, _) = CreateWithHttpContext();

// Act
string result = renderer.Render(LogEventInfo.CreateNullEvent());

// Assert
Assert.Equal("None", result);
}
#endif
}
}