6
6
using System . Linq ;
7
7
using System . Net ;
8
8
using System . Net . Http ;
9
+ using System . Net . WebSockets ;
10
+ using System . Text ;
11
+ using System . Threading ;
9
12
using System . Threading . Tasks ;
10
13
using Microsoft . AspNetCore . Builder ;
11
14
using Microsoft . AspNetCore . Hosting ;
@@ -23,7 +26,7 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate
23
26
{
24
27
// In theory this would work on Linux and Mac, but the client would require explicit credentials.
25
28
[ OSSkipCondition ( OperatingSystems . Linux | OperatingSystems . MacOSX ) ]
26
- public class NegotiateHandlerFunctionalTests
29
+ public class NegotiateHandlerFunctionalTests : LoggedTest
27
30
{
28
31
private static readonly Version Http11Version = new Version ( 1 , 1 ) ;
29
32
private static readonly Version Http2Version = new Version ( 2 , 0 ) ;
@@ -109,6 +112,34 @@ public async Task DefautCredentials_Success(Version version)
109
112
Assert . Equal ( Http11Version , result . Version ) ; // HTTP/2 downgrades.
110
113
}
111
114
115
+ [ ConditionalFact ]
116
+ public async Task DefautCredentials_WebSocket_Success ( )
117
+ {
118
+ using var host = await CreateHostAsync ( ) ;
119
+
120
+ var address = host . Services . GetRequiredService < IServer > ( ) . Features . Get < IServerAddressesFeature > ( ) . Addresses . First ( ) . Replace ( "https://" , "wss://" ) ;
121
+
122
+ using var webSocket = new ClientWebSocket
123
+ {
124
+ Options =
125
+ {
126
+ RemoteCertificateValidationCallback = ( sender , certificate , chain , sslPolicyErrors ) => true ,
127
+ UseDefaultCredentials = true ,
128
+ }
129
+ } ;
130
+
131
+ using var cts = new CancellationTokenSource ( TimeSpan . FromSeconds ( 30 ) ) ;
132
+
133
+ await webSocket . ConnectAsync ( new Uri ( $ "{ address } /AuthenticateWebSocket") , cts . Token ) ;
134
+
135
+ var receiveBuffer = new byte [ 13 ] ;
136
+ var receiveResult = await webSocket . ReceiveAsync ( receiveBuffer , cts . Token ) ;
137
+
138
+ Assert . True ( receiveResult . EndOfMessage ) ;
139
+ Assert . Equal ( WebSocketMessageType . Text , receiveResult . MessageType ) ;
140
+ Assert . Equal ( "Hello World!" , Encoding . UTF8 . GetString ( receiveBuffer , 0 , receiveResult . Count ) ) ;
141
+ }
142
+
112
143
public static IEnumerable < object [ ] > HttpOrders =>
113
144
new List < object [ ] >
114
145
{
@@ -232,9 +263,10 @@ public async Task UnauthorizedAfterAuthenticated_Success(Version version)
232
263
Assert . Equal ( Http11Version , result . Version ) ; // HTTP/2 downgrades.
233
264
}
234
265
235
- private static Task < IHost > CreateHostAsync ( Action < NegotiateOptions > configureOptions = null )
266
+ private Task < IHost > CreateHostAsync ( Action < NegotiateOptions > configureOptions = null )
236
267
{
237
268
var builder = new HostBuilder ( )
269
+ . ConfigureServices ( AddTestLogging )
238
270
. ConfigureServices ( services => services
239
271
. AddRouting ( )
240
272
. AddAuthentication ( NegotiateDefaults . AuthenticationScheme )
@@ -252,6 +284,7 @@ private static Task<IHost> CreateHostAsync(Action<NegotiateOptions> configureOpt
252
284
{
253
285
app . UseRouting ( ) ;
254
286
app . UseAuthentication ( ) ;
287
+ app . UseWebSockets ( ) ;
255
288
app . UseEndpoints ( ConfigureEndpoints ) ;
256
289
} ) ;
257
290
} ) ;
@@ -289,6 +322,27 @@ private static void ConfigureEndpoints(IEndpointRouteBuilder builder)
289
322
await context . Response . WriteAsync ( name ) ;
290
323
} ) ;
291
324
325
+ builder . Map ( "/AuthenticateWebSocket" , async context =>
326
+ {
327
+ if ( ! context . User . Identity . IsAuthenticated )
328
+ {
329
+ await context . ChallengeAsync ( ) ;
330
+ return ;
331
+ }
332
+
333
+ if ( ! context . WebSockets . IsWebSocketRequest )
334
+ {
335
+ context . Response . StatusCode = 400 ;
336
+ return ;
337
+ }
338
+
339
+ Assert . False ( string . IsNullOrEmpty ( context . User . Identity . Name ) , "name" ) ;
340
+
341
+ WebSocket webSocket = await context . WebSockets . AcceptWebSocketAsync ( ) ;
342
+
343
+ await webSocket . SendAsync ( Encoding . UTF8 . GetBytes ( "Hello World!" ) , WebSocketMessageType . Text , endOfMessage : true , context . RequestAborted ) ;
344
+ } ) ;
345
+
292
346
builder . Map ( "/AlreadyAuthenticated" , async context =>
293
347
{
294
348
Assert . Equal ( "HTTP/1.1" , context . Request . Protocol ) ; // Not HTTP/2
0 commit comments