7
7
using System . Diagnostics ;
8
8
using System . IO ;
9
9
using System . IO . Pipelines ;
10
+ using System . Security . Claims ;
11
+ using System . Security . Principal ;
10
12
using System . Threading ;
11
13
using System . Threading . Tasks ;
12
14
using Microsoft . AspNetCore . Connections ;
13
- using Microsoft . AspNetCore . Connections . Features ;
14
- using Microsoft . AspNetCore . Http . Connections . Features ;
15
15
using Microsoft . AspNetCore . Http . Connections . Internal . Transports ;
16
16
using Microsoft . AspNetCore . Http . Features ;
17
17
using Microsoft . AspNetCore . Internal ;
@@ -608,9 +608,6 @@ private async Task<bool> EnsureConnectionStateAsync(HttpConnectionContext connec
608
608
return false ;
609
609
}
610
610
611
- // Setup the connection state from the http context
612
- connection . User = context . User ;
613
-
614
611
// Configure transport-specific features.
615
612
if ( transportType == HttpTransportType . LongPolling )
616
613
{
@@ -630,21 +627,49 @@ private async Task<bool> EnsureConnectionStateAsync(HttpConnectionContext connec
630
627
{
631
628
// Set the request trace identifier to the current http request handling the poll
632
629
existing . TraceIdentifier = context . TraceIdentifier ;
633
- existing . User = context . User ;
630
+
631
+ // Don't copy the identity if it's a windows identity
632
+ // We specifically clone the identity on first poll if it's a windows identity
633
+ // If we swapped the new User here we'd have to dispose the old identities which could race with the application
634
+ // trying to access the identity.
635
+ if ( context . User . Identity is WindowsIdentity )
636
+ {
637
+ existing . User = context . User ;
638
+ }
634
639
}
635
640
}
636
641
else
637
642
{
638
643
connection . HttpContext = context ;
639
644
}
640
645
646
+ // Setup the connection state from the http context
647
+ connection . User = connection . HttpContext . User ;
648
+
641
649
// Set the Connection ID on the logging scope so that logs from now on will have the
642
650
// Connection ID metadata set.
643
651
logScope . ConnectionId = connection . ConnectionId ;
644
652
645
653
return true ;
646
654
}
647
655
656
+ private static void CloneUser ( HttpContext newContext , HttpContext oldContext )
657
+ {
658
+ if ( oldContext . User . Identity is WindowsIdentity )
659
+ {
660
+ newContext . User = new ClaimsPrincipal ( ) ;
661
+
662
+ foreach ( var identity in oldContext . User . Identities )
663
+ {
664
+ newContext . User . AddIdentity ( identity . Clone ( ) ) ;
665
+ }
666
+ }
667
+ else
668
+ {
669
+ newContext . User = oldContext . User ;
670
+ }
671
+ }
672
+
648
673
private static HttpContext CloneHttpContext ( HttpContext context )
649
674
{
650
675
// The reason we're copying the base features instead of the HttpContext properties is
@@ -692,7 +717,8 @@ private static HttpContext CloneHttpContext(HttpContext context)
692
717
693
718
var newHttpContext = new DefaultHttpContext ( features ) ;
694
719
newHttpContext . TraceIdentifier = context . TraceIdentifier ;
695
- newHttpContext . User = context . User ;
720
+
721
+ CloneUser ( newHttpContext , context ) ;
696
722
697
723
// Making request services function property could be tricky and expensive as it would require
698
724
// DI scope per connection. It would also mean that services resolved in middleware leading up to here
0 commit comments