diff --git a/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml b/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml
index e252c1c8ac5b..e3491cc9cace 100644
--- a/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml
+++ b/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml
@@ -48,12 +48,10 @@
-
-
diff --git a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Core.cs b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Core.cs
index 7df6633754ff..8383184bfa0f 100644
--- a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Core.cs
+++ b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Core.cs
@@ -16,7 +16,6 @@
using Datadog.Trace.Util.Http;
using Datadog.Trace.Vendors.Serilog.Events;
using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Primitives;
diff --git a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinatorHelpers.Core.cs b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinatorHelpers.Core.cs
index f0f7c2659912..523af9c3ddaf 100644
--- a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinatorHelpers.Core.cs
+++ b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinatorHelpers.Core.cs
@@ -7,10 +7,11 @@
#if !NETFRAMEWORK
using System;
using System.Collections.Generic;
+using System.Reflection;
using Datadog.Trace.AppSec.Waf;
+using Datadog.Trace.DuckTyping;
using Datadog.Trace.Logging;
using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Routing;
@@ -20,6 +21,8 @@ internal static class SecurityCoordinatorHelpers
{
private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor(typeof(SecurityCoordinatorHelpers));
+ internal static readonly Type? SessionFeature = Assembly.GetAssembly(typeof(IHeaderDictionary))?.GetType("Microsoft.AspNetCore.Http.Features.ISessionFeature", throwOnError: false);
+
internal static void CheckAndBlock(this Security security, HttpContext context, Span span)
{
if (security.AppsecEnabled)
@@ -82,9 +85,16 @@ internal static void CheckPathParamsAndSessionId(this Security security, HttpCon
var args = new Dictionary { { AddressesConstants.RequestPathParams, pathParams } };
IResult? result;
// we need to check context.Features.Get as accessing the Session item if session has not been configured for the application is throwing InvalidOperationException
- if (context.Features.Get() is { Session.IsAvailable: true } feature)
+ var sessionFeature = context.Features[SessionFeature];
+ Datadog.Trace.ClrProfiler.AutoInstrumentation.AspNetCore.UserEvents.ISessionFeature? sessionFeatureProxy = null;
+ if (sessionFeature is not null)
+ {
+ sessionFeatureProxy = sessionFeature.DuckCast();
+ }
+
+ if (sessionFeatureProxy?.Session?.IsAvailable == true)
{
- result = securityCoordinator.RunWaf(args, sessionId: feature.Session.Id);
+ result = securityCoordinator.RunWaf(args, sessionId: sessionFeatureProxy.Session.Id);
}
else
{
diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNetCore/UserEvents/HttpContextSetUser.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNetCore/UserEvents/HttpContextSetUser.cs
index b2d69da601ed..3195217bf403 100644
--- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNetCore/UserEvents/HttpContextSetUser.cs
+++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNetCore/UserEvents/HttpContextSetUser.cs
@@ -13,6 +13,7 @@
using Datadog.Trace.AppSec.Coordinator;
using Datadog.Trace.ClrProfiler.CallTarget;
using Datadog.Trace.Configuration;
+using Datadog.Trace.DuckTyping;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
@@ -90,8 +91,15 @@ internal static CallTargetState OnMethodBegin(TTarget instance, ref Cla
}
}
- var sessionId = httpContext.Features.Get()?.Session?.Id;
- var result = secCoord.RunWafForUser(userSessionId: sessionId, userId: userId);
+ ISessionFeature? sessionFeatureProxy = null;
+ var sessionFeature = httpContext.Features[SecurityCoordinatorHelpers.SessionFeature];
+
+ if (sessionFeature is not null)
+ {
+ sessionFeatureProxy = sessionFeature.DuckCast();
+ }
+
+ var result = secCoord.RunWafForUser(userSessionId: sessionFeatureProxy?.Session?.Id, userId: userId);
secCoord.BlockAndReport(result);
UserEventsCommon.RecordMetricsLoginSuccessIfNotFound(foundUserId, true);
diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNetCore/UserEvents/ISession.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNetCore/UserEvents/ISession.cs
new file mode 100644
index 000000000000..c501379b47d5
--- /dev/null
+++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNetCore/UserEvents/ISession.cs
@@ -0,0 +1,29 @@
+//
+// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
+// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
+//
+
+#if !NETFRAMEWORK
+#nullable enable
+using System.ComponentModel;
+
+namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AspNetCore.UserEvents;
+
+///
+/// Duck type of the SignInManager aspnet core type
+///
+[Browsable(false)]
+[EditorBrowsable(EditorBrowsableState.Never)]
+public interface ISession
+{
+ ///
+ /// Gets a value indicating whether the session is available
+ ///
+ bool IsAvailable { get; }
+
+ ///
+ /// Gets the session id
+ ///
+ string Id { get; }
+}
+#endif
diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNetCore/UserEvents/ISessionFeature.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNetCore/UserEvents/ISessionFeature.cs
new file mode 100644
index 000000000000..afb8ddc8d880
--- /dev/null
+++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNetCore/UserEvents/ISessionFeature.cs
@@ -0,0 +1,24 @@
+//
+// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
+// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
+//
+
+#if !NETFRAMEWORK
+#nullable enable
+using System.ComponentModel;
+
+namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AspNetCore.UserEvents;
+
+///
+/// Duck type of the ISessionFeature aspnet core type in Microsoft.AspNetCore.Http.Features assembly
+///
+[Browsable(false)]
+[EditorBrowsable(EditorBrowsableState.Never)]
+public interface ISessionFeature
+{
+ ///
+ /// Gets the Session object, can be null
+ ///
+ public ISession Session { get; }
+}
+#endif
diff --git a/tracer/test/test-applications/security/Samples.Security.AspNetCore5/Controllers/SessionController.cs b/tracer/test/test-applications/security/Samples.Security.AspNetCore5/Controllers/SessionController.cs
new file mode 100644
index 000000000000..096e17f75ae1
--- /dev/null
+++ b/tracer/test/test-applications/security/Samples.Security.AspNetCore5/Controllers/SessionController.cs
@@ -0,0 +1,34 @@
+using System;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Formatters;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
+using Microsoft.AspNetCore.Routing;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Datadog.Trace;
+
+namespace weblog
+{
+ [ApiController]
+ [Route("session")]
+ public class SessionController : Controller
+ {
+ [HttpGet("new")]
+ public IActionResult New()
+ {
+ return Content(HttpContext.Session.Id);
+ }
+
+ [HttpGet("user")]
+ public IActionResult User(string sdk_user)
+ {
+ if (sdk_user != null)
+ {
+ Samples.SampleHelpers.TrackUserLoginSuccessEvent(sdk_user, null);
+ }
+
+ return Content($"Hello, set the user to {sdk_user}");
+ }
+ }
+}