1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.Generic;
6 using System.ComponentModel;
7 using System.Diagnostics;
8 using System.IO;
9 using System.Linq;
10 using System.Net.Test.Common;
11 using System.Security.Authentication;
12 using System.Security.Principal;
13 using System.Text;
14 using System.Threading.Tasks;
15 
16 using Xunit;
17 using Xunit.Abstractions;
18 using Xunit.NetCore.Extensions;
19 
20 namespace System.Net.Security.Tests
21 {
22     public class KDCSetup : IDisposable
23     {
24         private const string Krb5ConfigFile = "/etc/krb5.conf";
25         private const string KDestroyCmd = "kdestroy";
26         private const string ScriptName = "setup-kdc.sh";
27         private const string ScriptUninstallArgs = "--uninstall --yes";
28         private const string ScriptInstallArgs = "--password {0} --yes";
29         private const int InstalledButUnconfiguredExitCode = 2;
30         private readonly bool _isKrbPreInstalled;
31         public readonly string password;
32         private const string NtlmUserFile = "NTLM_USER_FILE";
33         private readonly bool _successfulSetup = true;
34 
KDCSetup()35         public KDCSetup()
36         {
37             _isKrbPreInstalled = File.Exists(Krb5ConfigFile) &&
38                 File.ReadAllText(Krb5ConfigFile).Contains(TestConfiguration.Realm);
39             if (!_isKrbPreInstalled)
40             {
41                 password = Guid.NewGuid().ToString("N");
42                 int exitCode = RunSetupScript(string.Format(ScriptInstallArgs, password));
43                 if (exitCode != 0)
44                 {
45                     if (exitCode != InstalledButUnconfiguredExitCode)
46                     {
47                         Dispose();
48                     }
49                     _successfulSetup = false;
50                 }
51             }
52             else
53             {
54                 password = TestConfiguration.DefaultPassword;
55             }
56         }
57 
Dispose()58         public void Dispose()
59         {
60             if (!_isKrbPreInstalled)
61             {
62                 RunSetupScript(ScriptUninstallArgs);
63             }
64         }
65 
66         // checks for availability of Kerberos related infrastructure
67         // on the host. Returns true available, false otherwise
CheckAndClearCredentials(ITestOutputHelper output)68         public bool CheckAndClearCredentials(ITestOutputHelper output)
69         {
70             if (!_successfulSetup)
71             {
72                 return false;
73             }
74 
75             // Clear the credentials
76             var startInfo = new ProcessStartInfo(KDestroyCmd);
77             startInfo.CreateNoWindow = true;
78             startInfo.Arguments = "-A";
79             using (Process clearCreds = Process.Start(startInfo))
80             {
81                 clearCreds.WaitForExit();
82                 output.WriteLine("kdestroy returned {0}", clearCreds.ExitCode);
83                 return (clearCreds.ExitCode == 0);
84             }
85         }
86 
CheckAndInitializeNtlm(bool isKrbAvailable)87         public bool CheckAndInitializeNtlm(bool isKrbAvailable)
88         {
89             if (!_successfulSetup || !isKrbAvailable)
90             {
91                 return false;
92             }
93 
94             if (File.Exists(TestConfiguration.NtlmUserFilePath))
95             {
96                 Environment.SetEnvironmentVariable(NtlmUserFile, TestConfiguration.NtlmUserFilePath);
97                 return true;
98             }
99 
100             return false;
101         }
102 
RunSetupScript(string args = null)103         private static int RunSetupScript(string args = null)
104         {
105             try
106             {
107                 return AdminHelpers.RunAsSudo($"bash {ScriptName} {args}");
108             }
109             catch
110             {
111                 // Could not find the file
112                 return 1;
113             }
114         }
115     }
116 
117     [Trait(XunitConstants.Category, XunitConstants.RequiresElevation)]
118     public class NegotiateStreamTest : IDisposable, IClassFixture<KDCSetup>
119     {
120         private readonly byte[] _firstMessage = Encoding.UTF8.GetBytes("Sample First Message");
121         private readonly byte[] _secondMessage = Encoding.UTF8.GetBytes("Sample Second Message");
122         private readonly bool _isKrbAvailable; // tests are no-op if kerberos is not available on the host machine
123         private readonly bool _isNtlmAvailable; // tests are no-op if ntlm is not available on the host machine
124         private readonly KDCSetup _fixture;
125         private readonly ITestOutputHelper _output;
126         private readonly string _emptyTarget = string.Empty;
127         private readonly string _testTarget = "TestTarget";
128         private static readonly string _ntlmPassword = TestConfiguration.NtlmPassword;
129 
AssertClientPropertiesForTarget(NegotiateStream client, string target)130         private void AssertClientPropertiesForTarget(NegotiateStream client, string target)
131         {
132             Assert.True(client.IsAuthenticated, "client.IsAuthenticated");
133             Assert.Equal(TokenImpersonationLevel.Identification, client.ImpersonationLevel);
134             Assert.True(client.IsEncrypted, "client.IsEncrypted");
135             Assert.True(client.IsMutuallyAuthenticated, "client.IsMutuallyAuthenticated");
136             Assert.False(client.IsServer, "client.IsServer");
137             Assert.True(client.IsSigned, "client.IsSigned");
138             Assert.False(client.LeaveInnerStreamOpen, "client.LeaveInnerStreamOpen");
139 
140             IIdentity serverIdentity = client.RemoteIdentity;
141             Assert.Equal("Kerberos", serverIdentity.AuthenticationType);
142             Assert.True(serverIdentity.IsAuthenticated, "serverIdentity.IsAuthenticated");
143             IdentityValidator.AssertHasName(serverIdentity, target);
144         }
145 
NegotiateStreamTest(KDCSetup fixture, ITestOutputHelper output)146         public NegotiateStreamTest(KDCSetup fixture, ITestOutputHelper output)
147         {
148             _fixture = fixture;
149             _output = output;
150             _isKrbAvailable = _fixture.CheckAndClearCredentials(_output);
151             _isNtlmAvailable = _fixture.CheckAndInitializeNtlm(_isKrbAvailable);
152         }
153 
154         [Fact, OuterLoop]
155         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_KerberosAuthentication_Success()156         public async Task NegotiateStream_StreamToStream_KerberosAuthentication_Success()
157         {
158             if (!_isKrbAvailable)
159             {
160                 _output.WriteLine("skipping NegotiateStream_StreamToStream_KerberosAuthentication_Success");
161                 return;
162             }
163 
164             VirtualNetwork network = new VirtualNetwork();
165 
166             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
167             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
168             using (var client = new NegotiateStream(clientStream))
169             using (var server = new UnixGssFakeNegotiateStream(serverStream))
170             {
171                 Assert.False(client.IsAuthenticated, "client is not authenticated");
172 
173                 string user = string.Format("{0}@{1}", TestConfiguration.KerberosUser, TestConfiguration.Realm);
174                 string target = string.Format("{0}@{1}", TestConfiguration.HostTarget, TestConfiguration.Realm);
175                 NetworkCredential credential = new NetworkCredential(user, _fixture.password);
176                 Task[] auth = new Task[] {
177                     client.AuthenticateAsClientAsync(credential, target),
178                     server.AuthenticateAsServerAsync()
179                 };
180 
181                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth);
182                 AssertClientPropertiesForTarget(client, target);
183             }
184         }
185 
186         [Fact, OuterLoop]
187         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_AuthToHttpTarget_Success()188         public async Task NegotiateStream_StreamToStream_AuthToHttpTarget_Success()
189         {
190             if (!_isKrbAvailable)
191             {
192                 _output.WriteLine("skipping NegotiateStream_StreamToStream_AuthToHttpTarget_Success");
193                 return;
194             }
195 
196             VirtualNetwork network = new VirtualNetwork();
197 
198             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
199             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
200             using (var client = new NegotiateStream(clientStream))
201             using (var server = new UnixGssFakeNegotiateStream(serverStream))
202             {
203                 Assert.False(client.IsAuthenticated);
204 
205                 string user = string.Format("{0}@{1}", TestConfiguration.KerberosUser, TestConfiguration.Realm);
206                 NetworkCredential credential = new NetworkCredential(user, _fixture.password);
207                 Task[] auth = new Task[] {
208                     client.AuthenticateAsClientAsync(credential, TestConfiguration.HttpTarget),
209                     server.AuthenticateAsServerAsync()
210                 };
211 
212                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth);
213 
214                 AssertClientPropertiesForTarget(client, TestConfiguration.HttpTarget);
215             }
216         }
217 
218         [Fact, OuterLoop]
219         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_KerberosAuthWithoutRealm_Success()220         public async Task NegotiateStream_StreamToStream_KerberosAuthWithoutRealm_Success()
221         {
222             if (!_isKrbAvailable)
223             {
224                 _output.WriteLine("skipping NegotiateStream_StreamToStream_KerberosAuthWithoutRealm_Success");
225                 return;
226             }
227 
228             VirtualNetwork network = new VirtualNetwork();
229 
230             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
231             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
232             using (var client = new NegotiateStream(clientStream))
233             using (var server = new UnixGssFakeNegotiateStream(serverStream))
234             {
235                 Assert.False(client.IsAuthenticated);
236 
237                 NetworkCredential credential = new NetworkCredential(TestConfiguration.KerberosUser, _fixture.password);
238                 Task[] auth = new Task[] {
239                     client.AuthenticateAsClientAsync(credential, TestConfiguration.HostTarget),
240                     server.AuthenticateAsServerAsync()
241                 };
242 
243                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth);
244 
245                 AssertClientPropertiesForTarget(client, TestConfiguration.HostTarget);
246             }
247         }
248 
249         [Fact, OuterLoop]
250         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_KerberosAuthDefaultCredentials_Success()251         public async Task NegotiateStream_StreamToStream_KerberosAuthDefaultCredentials_Success()
252         {
253             if (!_isKrbAvailable)
254             {
255                 _output.WriteLine("skipping NegotiateStream_StreamToStream_KerberosAuthDefaultCredentials_Success");
256                 return;
257             }
258 
259             VirtualNetwork network = new VirtualNetwork();
260 
261             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
262             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
263             using (var client = new NegotiateStream(clientStream))
264             using (var server = new UnixGssFakeNegotiateStream(serverStream))
265             {
266                 Assert.False(client.IsAuthenticated, "client is not authenticated before AuthenticateAsClient call");
267 
268                 string user = string.Format("{0}@{1}", TestConfiguration.KerberosUser, TestConfiguration.Realm);
269                 string target = string.Format("{0}@{1}", TestConfiguration.HostTarget, TestConfiguration.Realm);
270                 // Seed the default Kerberos cache with the TGT
271                 UnixGssFakeNegotiateStream.GetDefaultKerberosCredentials(user, _fixture.password);
272                 Task[] auth = new Task[] {
273                     client.AuthenticateAsClientAsync(CredentialCache.DefaultNetworkCredentials, target),
274                     server.AuthenticateAsServerAsync()
275                 };
276 
277                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth);
278 
279                 AssertClientPropertiesForTarget(client, target);
280             }
281         }
282 
283         [Fact, OuterLoop]
284         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_EchoServer_ClientWriteRead_Successive_Sync_Success()285         public async Task NegotiateStream_EchoServer_ClientWriteRead_Successive_Sync_Success()
286         {
287             if (!_isKrbAvailable)
288             {
289                 _output.WriteLine("skipping NegotiateStream_EchoServer_ClientWriteRead_Successive_Sync_Success");
290                 return;
291             }
292 
293             VirtualNetwork network = new VirtualNetwork();
294             byte[] firstRecvBuffer = new byte[_firstMessage.Length];
295             byte[] secondRecvBuffer = new byte[_secondMessage.Length];
296 
297             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
298             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
299             using (var client = new NegotiateStream(clientStream))
300             using (var server = new UnixGssFakeNegotiateStream(serverStream))
301             {
302                 Assert.False(client.IsAuthenticated, "client is not authenticated before AuthenticateAsClient call");
303 
304                 string user = string.Format("{0}@{1}", TestConfiguration.KerberosUser, TestConfiguration.Realm);
305                 string target = string.Format("{0}@{1}", TestConfiguration.HostTarget, TestConfiguration.Realm);
306                 NetworkCredential credential = new NetworkCredential(user, _fixture.password);
307                 Task[] auth = new Task[] {
308                     client.AuthenticateAsClientAsync(credential, target),
309                     server.AuthenticateAsServerAsync()
310                 };
311                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth);
312 
313                 Task svrMsgTask = server.PollMessageAsync(2);
314 
315                 client.Write(_firstMessage, 0, _firstMessage.Length);
316                 client.Write(_secondMessage, 0, _secondMessage.Length);
317                 client.Read(firstRecvBuffer, 0, firstRecvBuffer.Length);
318                 client.Read(secondRecvBuffer, 0, secondRecvBuffer.Length);
319                 Assert.True(_firstMessage.SequenceEqual(firstRecvBuffer), "first message received is as expected");
320                 Assert.True(_secondMessage.SequenceEqual(secondRecvBuffer), "second message received is as expected");
321                 await svrMsgTask.TimeoutAfter(TestConfiguration.PassingTestTimeoutMilliseconds);
322             }
323         }
324 
325         [Fact, OuterLoop]
326         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_EchoServer_ClientWriteRead_Successive_Async_Success()327         public async Task NegotiateStream_EchoServer_ClientWriteRead_Successive_Async_Success()
328         {
329             if (!_isKrbAvailable)
330             {
331                 _output.WriteLine("skipping NegotiateStream_EchoServer_ClientWriteRead_Successive_Async_Success");
332                 return;
333             }
334 
335             VirtualNetwork network = new VirtualNetwork();
336             byte[] firstRecvBuffer = new byte[_firstMessage.Length];
337             byte[] secondRecvBuffer = new byte[_secondMessage.Length];
338 
339             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
340             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
341             using (var client = new NegotiateStream(clientStream))
342             using (var server = new UnixGssFakeNegotiateStream(serverStream))
343             {
344                 Assert.False(client.IsAuthenticated, "client is not authenticated before AuthenticateAsClient call");
345 
346                 string user = string.Format("{0}@{1}", TestConfiguration.KerberosUser, TestConfiguration.Realm);
347                 string target = string.Format("{0}@{1}", TestConfiguration.HostTarget, TestConfiguration.Realm);
348                 NetworkCredential credential = new NetworkCredential(user, _fixture.password);
349                 Task[] auth = new Task[] {
350                     client.AuthenticateAsClientAsync(credential, target),
351                     server.AuthenticateAsServerAsync()
352                 };
353 
354                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth);
355 
356                 Task serverTask = server.PollMessageAsync(2);
357                 Task[] msgTasks = new Task[] {
358                  client.WriteAsync(_firstMessage, 0, _firstMessage.Length).ContinueWith((t) =>
359                     client.WriteAsync(_secondMessage, 0, _secondMessage.Length)).Unwrap(),
360                  ReadAllAsync(client, firstRecvBuffer, 0, firstRecvBuffer.Length).ContinueWith((t) =>
361                    ReadAllAsync(client, secondRecvBuffer, 0, secondRecvBuffer.Length)).Unwrap(),
362                  serverTask
363                 };
364 
365                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(msgTasks);
366 
367                 Assert.True(_firstMessage.SequenceEqual(firstRecvBuffer), "The first message received is as expected");
368                 Assert.True(_secondMessage.SequenceEqual(secondRecvBuffer), "The second message received is as expected");
369             }
370         }
371 
ReadAllAsync(Stream source, byte[] buffer, int offset, int count)372         private static async Task ReadAllAsync(Stream source, byte[] buffer, int offset, int count)
373         {
374             while (count > 0)
375             {
376                 int bytesRead = await source.ReadAsync(buffer, offset, count).ConfigureAwait(false);
377                 if (bytesRead == 0) break;
378                 offset += bytesRead;
379                 count -= bytesRead;
380             }
381         }
382 
383         [Fact, OuterLoop]
384         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_KerberosAuthDefaultCredentialsNoSeed_Failure()385         public void NegotiateStream_StreamToStream_KerberosAuthDefaultCredentialsNoSeed_Failure()
386         {
387             if (!_isKrbAvailable)
388             {
389                 _output.WriteLine("skipping NegotiateStream_StreamToStream_KerberosAuthDefaultCredentialsNoSeed_Failure");
390                 return;
391             }
392 
393             VirtualNetwork network = new VirtualNetwork();
394 
395             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
396             using (var client = new NegotiateStream(clientStream))
397             {
398                 Assert.False(client.IsAuthenticated, "client is not authenticated before AuthenticateAsClient call");
399 
400                 string user = string.Format("{0}@{1}", TestConfiguration.KerberosUser, TestConfiguration.Realm);
401                 string target = string.Format("{0}@{1}", TestConfiguration.HostTarget, TestConfiguration.Realm);
402                 Assert.ThrowsAsync<AuthenticationException>(() => client.AuthenticateAsClientAsync(CredentialCache.DefaultNetworkCredentials, target));
403             }
404         }
405 
406         [Fact, OuterLoop]
407         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_KerberosAuthInvalidUser_Failure()408         public void NegotiateStream_StreamToStream_KerberosAuthInvalidUser_Failure()
409         {
410             if (!_isKrbAvailable)
411             {
412                 _output.WriteLine("skipping NegotiateStream_StreamToStream_KerberosAuthInvalidUser_Failure");
413                 return;
414             }
415 
416             VirtualNetwork network = new VirtualNetwork();
417 
418             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
419             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
420             using (var client = new NegotiateStream(clientStream))
421             using (var server = new UnixGssFakeNegotiateStream(serverStream))
422             {
423                 Assert.False(client.IsAuthenticated, "client is not authenticated by default");
424 
425                 string user = string.Format("{0}@{1}", TestConfiguration.KerberosUser, TestConfiguration.Realm);
426                 string target = string.Format("{0}@{1}", TestConfiguration.HostTarget, TestConfiguration.Realm);
427                 NetworkCredential credential = new NetworkCredential(user.Substring(1), _fixture.password);
428                 Assert.ThrowsAsync<AuthenticationException>(() => client.AuthenticateAsClientAsync(credential, target));
429                 Assert.ThrowsAsync<AuthenticationException>(() => server.AuthenticateAsServerAsync());
430             }
431         }
432 
433         [Fact, OuterLoop]
434         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_KerberosAuthInvalidPassword_Failure()435         public void NegotiateStream_StreamToStream_KerberosAuthInvalidPassword_Failure()
436         {
437             if (!_isKrbAvailable)
438             {
439                 _output.WriteLine("skipping NegotiateStream_StreamToStream_KerberosAuthInvalidPassword_Failure");
440                 return;
441             }
442 
443             VirtualNetwork network = new VirtualNetwork();
444 
445             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
446             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
447             using (var client = new NegotiateStream(clientStream))
448             using (var server = new UnixGssFakeNegotiateStream(serverStream))
449             {
450                 Assert.False(client.IsAuthenticated, "client stream is not authenticated by default");
451 
452                 string user = string.Format("{0}@{1}", TestConfiguration.KerberosUser, TestConfiguration.Realm);
453                 string target = string.Format("{0}@{1}", TestConfiguration.HostTarget, TestConfiguration.Realm);
454                 NetworkCredential credential = new NetworkCredential(user, _fixture.password.Substring(1));
455                 Task serverAuth = server.AuthenticateAsServerAsync();
456                 Assert.ThrowsAsync<AuthenticationException>(() => client.AuthenticateAsClientAsync(credential, target));
457                 Assert.ThrowsAsync<AuthenticationException>(() => server.AuthenticateAsServerAsync());
458             }
459         }
460 
461         [Fact, OuterLoop]
462         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_KerberosAuthInvalidTarget_Failure()463         public void NegotiateStream_StreamToStream_KerberosAuthInvalidTarget_Failure()
464         {
465             if (!_isKrbAvailable)
466             {
467                 _output.WriteLine("skipping NegotiateStream_StreamToStream_KerberosAuthInvalidTarget_Failure");
468                 return;
469             }
470 
471             VirtualNetwork network = new VirtualNetwork();
472 
473             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
474             using (var client = new NegotiateStream(clientStream))
475             {
476                 Assert.False(client.IsAuthenticated, "client stream is not authenticated by default");
477 
478                 string user = string.Format("{0}@{1}", TestConfiguration.KerberosUser, TestConfiguration.Realm);
479                 string target = string.Format("{0}@{1}", TestConfiguration.HostTarget, TestConfiguration.Realm);
480                 NetworkCredential credential = new NetworkCredential(user, _fixture.password);
481                 Assert.ThrowsAsync<AuthenticationException>(() => client.AuthenticateAsClientAsync(credential, target.Substring(1)));
482             }
483         }
484 
ValidNtlmCredentials()485         public static IEnumerable<object[]> ValidNtlmCredentials()
486         {
487 
488             yield return new object[] { new NetworkCredential(TestConfiguration.NtlmUser, _ntlmPassword, TestConfiguration.Domain) };
489             yield return new object[] { new NetworkCredential(TestConfiguration.NtlmUser, _ntlmPassword) };
490             yield return new object[]
491             {
492                     new NetworkCredential($@"{TestConfiguration.Domain}\{TestConfiguration.NtlmUser}", _ntlmPassword)
493             };
494             yield return new object[]
495             {
496                     new NetworkCredential($"{TestConfiguration.NtlmUser}@{TestConfiguration.Domain}", _ntlmPassword)
497             };
498         }
499 
500         public static IEnumerable<object[]> InvalidNtlmCredentials
501         {
502             get
503             {
504                 yield return new object[] { new NetworkCredential(TestConfiguration.NtlmUser, _ntlmPassword, TestConfiguration.Domain.Substring(1)) };
505                 yield return new object[] { new NetworkCredential(TestConfiguration.NtlmUser.Substring(1), _ntlmPassword, TestConfiguration.Domain) };
506                 yield return new object[] { new NetworkCredential(TestConfiguration.NtlmUser, _ntlmPassword.Substring(1), TestConfiguration.Domain) };
507                 yield return new object[] { new NetworkCredential($@"{TestConfiguration.Domain}\{TestConfiguration.NtlmUser}", _ntlmPassword, TestConfiguration.Domain.Substring(1)) };
508                 yield return new object[] { new NetworkCredential($"{TestConfiguration.NtlmUser}@{TestConfiguration.Domain.Substring(1)}", _ntlmPassword) };
509                 yield return new object[] { new NetworkCredential($@"{TestConfiguration.Domain.Substring(1)}\{TestConfiguration.NtlmUser}", _ntlmPassword, TestConfiguration.Domain) };
510                 yield return new object[] { new NetworkCredential(TestConfiguration.NtlmUser, _ntlmPassword, TestConfiguration.Realm) };
511 
512             }
513         }
514 
515 
516         [Theory, OuterLoop]
517         [MemberData(nameof(ValidNtlmCredentials))]
518         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_NtlmAuthentication_ValidCredentials_Success(NetworkCredential credential)519         public async Task NegotiateStream_StreamToStream_NtlmAuthentication_ValidCredentials_Success(NetworkCredential credential)
520         {
521             if (!_isNtlmAvailable)
522             {
523                 _output.WriteLine("skipping NegotiateStream_StreamToStream_NtlmAuthentication_ValidCredentials_Success");
524                 return;
525             }
526 
527             VirtualNetwork network = new VirtualNetwork();
528 
529             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
530             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
531             using (var client = new NegotiateStream(clientStream))
532             using (var server = new UnixGssFakeNegotiateStream(serverStream))
533             {
534                 Assert.False(client.IsAuthenticated, "client.IsAuthenticated");
535                 Assert.False(server.IsAuthenticated, "server.IsAuthenticated");
536 
537                 Task[] auth = new Task[] {
538                     client.AuthenticateAsClientAsync(credential, _testTarget, ProtectionLevel.None, TokenImpersonationLevel.Identification),
539                     server.AuthenticateAsServerAsync()
540                 };
541 
542                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth);
543 
544                 // Expected Client property values:
545                 Assert.True(client.IsAuthenticated, "client.IsAuthenticated");
546                 Assert.Equal(TokenImpersonationLevel.Identification, client.ImpersonationLevel);
547                 Assert.False(client.IsEncrypted, "client.IsEncrypted");
548                 Assert.False(client.IsMutuallyAuthenticated, "client.IsMutuallyAuthenticated");
549                 Assert.False(client.IsServer, "client.IsServer");
550                 Assert.False(client.IsSigned, "client.IsSigned");
551                 Assert.False(client.LeaveInnerStreamOpen, "client.LeaveInnerStreamOpen");
552 
553                 IIdentity serverIdentity = client.RemoteIdentity;
554                 Assert.Equal("NTLM", serverIdentity.AuthenticationType);
555                 Assert.True(serverIdentity.IsAuthenticated, "serverIdentity.IsAuthenticated");
556                 IdentityValidator.AssertHasName(serverIdentity, _testTarget);
557             }
558         }
559 
560 
561         [Fact, OuterLoop]
562         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_NtlmAuthentication_Fallback_Success()563         public async Task NegotiateStream_StreamToStream_NtlmAuthentication_Fallback_Success()
564         {
565             if (!_isNtlmAvailable)
566             {
567                 _output.WriteLine("skipping NegotiateStream_StreamToStream_NtlmAuthentication_EmptyTarget_KerberosUser_Fallback_Success");
568                 return;
569             }
570 
571             VirtualNetwork network = new VirtualNetwork();
572 
573             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
574             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
575             using (var client = new NegotiateStream(clientStream))
576             using (var server = new UnixGssFakeNegotiateStream(serverStream))
577             {
578                 Assert.False(client.IsAuthenticated, "client.IsAuthenticated");
579                 Assert.False(server.IsAuthenticated, "server.IsAuthenticated");
580 
581                 string user = string.Format("{0}@{1}", TestConfiguration.NtlmUser, TestConfiguration.Domain);
582                 NetworkCredential credential = new NetworkCredential(user, TestConfiguration.NtlmPassword);
583                 Task[] auth = new Task[] {
584                     client.AuthenticateAsClientAsync(credential, TestConfiguration.HostTarget),
585                     server.AuthenticateAsServerAsync()
586                 };
587 
588                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth);
589 
590                 // Expected Client property values:
591                 Assert.True(client.IsAuthenticated, "client.IsAuthenticated");
592                 Assert.Equal(TokenImpersonationLevel.Identification, client.ImpersonationLevel);
593                 Assert.True(client.IsEncrypted, "client.IsEncrypted");
594                 Assert.False(client.IsMutuallyAuthenticated, "client.IsMutuallyAuthenticated");
595                 Assert.False(client.IsServer, "client.IsServer");
596                 Assert.True(client.IsSigned, "client.IsSigned");
597                 Assert.False(client.LeaveInnerStreamOpen, "client.LeaveInnerStreamOpen");
598 
599                 IIdentity serverIdentity = client.RemoteIdentity;
600                 Assert.Equal("NTLM", serverIdentity.AuthenticationType);
601                 Assert.False(serverIdentity.IsAuthenticated, "serverIdentity.IsAuthenticated");
602             }
603         }
604 
605         [Fact, OuterLoop]
606         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_NtlmAuthentication_KerberosCreds_Success()607         public async Task NegotiateStream_StreamToStream_NtlmAuthentication_KerberosCreds_Success()
608         {
609             if (!_isNtlmAvailable)
610             {
611                 _output.WriteLine("skipping NegotiateStream_StreamToStream_NtlmAuthentication_KerberosCreds_Success");
612                 return;
613             }
614 
615             VirtualNetwork network = new VirtualNetwork();
616 
617             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
618             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
619             using (var client = new NegotiateStream(clientStream))
620             using (var server = new UnixGssFakeNegotiateStream(serverStream))
621             {
622                 Assert.False(client.IsAuthenticated, "client.IsAuthenticated");
623                 Assert.False(server.IsAuthenticated, "server.IsAuthenticated");
624 
625                 string user = string.Format("{0}@{1}", TestConfiguration.KerberosUser, TestConfiguration.Realm);
626                 NetworkCredential credential = new NetworkCredential(user, _fixture.password);
627                 Task[] auth = new Task[] {
628                     client.AuthenticateAsClientAsync(credential, TestConfiguration.HttpTarget, ProtectionLevel.None, TokenImpersonationLevel.Identification),
629                     server.AuthenticateAsServerAsync()
630                 };
631                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth);
632 
633                 // Expected Client property values:
634                 Assert.True(client.IsAuthenticated, "client.IsAuthenticated");
635                 Assert.Equal(TokenImpersonationLevel.Identification, client.ImpersonationLevel);
636                 Assert.False(client.IsEncrypted, "client.IsEncrypted");
637                 Assert.False(client.IsMutuallyAuthenticated, "client.IsMutuallyAuthenticated");
638                 Assert.False(client.IsServer, "client.IsServer");
639                 Assert.False(client.IsSigned, "client.IsSigned");
640                 Assert.False(client.LeaveInnerStreamOpen, "client.LeaveInnerStreamOpen");
641 
642                 IIdentity serverIdentity = client.RemoteIdentity;
643                 Assert.Equal("NTLM", serverIdentity.AuthenticationType);
644                 Assert.True(serverIdentity.IsAuthenticated, "server identity is authenticated");
645                 IdentityValidator.AssertHasName(serverIdentity, TestConfiguration.HttpTarget);
646             }
647         }
648 
649         [Fact, OuterLoop]
650         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_EchoServer_NTLM_ClientWriteRead_Successive_Sync_Success()651         public async Task NegotiateStream_EchoServer_NTLM_ClientWriteRead_Successive_Sync_Success()
652         {
653             if (!_isNtlmAvailable)
654             {
655                 _output.WriteLine("skipping NegotiateStream_EchoServer_NTLM_ClientWriteRead_Successive_Sync_Success");
656                 return;
657             }
658 
659             byte[] firstRecvBuffer = new byte[_firstMessage.Length];
660             byte[] secondRecvBuffer = new byte[_secondMessage.Length];
661 
662             VirtualNetwork network = new VirtualNetwork();
663 
664             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
665             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
666             using (var client = new NegotiateStream(clientStream))
667             using (var server = new UnixGssFakeNegotiateStream(serverStream))
668             {
669                 Assert.False(client.IsAuthenticated, "client.IsAuthenticated");
670                 Assert.False(server.IsAuthenticated, "server.IsAuthenticated");
671 
672                 string user = string.Format("{0}@{1}", TestConfiguration.NtlmUser, TestConfiguration.Domain);
673                 NetworkCredential credential = new NetworkCredential(user, TestConfiguration.NtlmPassword);
674                 Task[] auth = new Task[] {
675                     client.AuthenticateAsClientAsync(credential, TestConfiguration.HostTarget),
676                     server.AuthenticateAsServerAsync()
677                 };
678                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth);
679 
680                 //clearing message queue
681                 byte[] junkBytes = new byte[5];
682                 int j = clientStream.Read(junkBytes, 0, 5);
683                 Task svrMsgTask = server.PollMessageAsync(2);
684 
685                 client.Write(_firstMessage, 0, _firstMessage.Length);
686                 client.Write(_secondMessage, 0, _secondMessage.Length);
687                 client.Read(firstRecvBuffer, 0, firstRecvBuffer.Length);
688                 client.Read(secondRecvBuffer, 0, secondRecvBuffer.Length);
689                 Assert.True(_firstMessage.SequenceEqual(firstRecvBuffer), "first message received is as expected");
690                 Assert.True(_secondMessage.SequenceEqual(secondRecvBuffer), "second message received is as expected");
691                 await svrMsgTask.TimeoutAfter(TestConfiguration.PassingTestTimeoutMilliseconds);
692             }
693         }
694 
695         [Fact, OuterLoop]
696         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_EchoServer_NTLM_ClientWriteRead_Successive_Async_Success()697         public async Task NegotiateStream_EchoServer_NTLM_ClientWriteRead_Successive_Async_Success()
698         {
699             if (!_isNtlmAvailable)
700             {
701                 _output.WriteLine("skipping NegotiateStream_EchoServer_NTLM_ClientWriteRead_Successive_Async_Success");
702                 return;
703             }
704 
705             byte[] firstRecvBuffer = new byte[_firstMessage.Length];
706             byte[] secondRecvBuffer = new byte[_secondMessage.Length];
707 
708             VirtualNetwork network = new VirtualNetwork();
709 
710             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
711             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
712             using (var client = new NegotiateStream(clientStream))
713             using (var server = new UnixGssFakeNegotiateStream(serverStream))
714             {
715                 Assert.False(client.IsAuthenticated, "client.IsAuthenticated");
716                 Assert.False(server.IsAuthenticated, "server.IsAuthenticated");
717 
718                 string user = string.Format("{0}@{1}", TestConfiguration.NtlmUser, TestConfiguration.Domain);
719                 NetworkCredential credential = new NetworkCredential(user, TestConfiguration.NtlmPassword);
720                 Task[] auth = new Task[] {
721                     client.AuthenticateAsClientAsync(credential, TestConfiguration.HostTarget),
722                     server.AuthenticateAsServerAsync()
723                 };
724 
725                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth);
726 
727                 //clearing message queue
728                 byte[] junkBytes = new byte[5];
729                 int j = clientStream.Read(junkBytes, 0, 5);
730                 Task serverTask = server.PollMessageAsync(2);
731 
732                 Task[] msgTasks = new Task[] {
733                  client.WriteAsync(_firstMessage, 0, _firstMessage.Length).ContinueWith((t) =>
734                     client.WriteAsync(_secondMessage, 0, _secondMessage.Length)).Unwrap(),
735                  ReadAllAsync(client, firstRecvBuffer, 0, firstRecvBuffer.Length).ContinueWith((t) =>
736                    ReadAllAsync(client, secondRecvBuffer, 0, secondRecvBuffer.Length)).Unwrap(),
737                  serverTask
738                 };
739 
740                 await TestConfiguration.WhenAllOrAnyFailedWithTimeout(msgTasks);
741                 Assert.True(_firstMessage.SequenceEqual(firstRecvBuffer), "The first message received is as expected");
742                 Assert.True(_secondMessage.SequenceEqual(secondRecvBuffer), "The second message received is as expected");
743             }
744         }
745 
746         [Theory, OuterLoop]
747         [MemberData(nameof(InvalidNtlmCredentials))]
748         [PlatformSpecific(TestPlatforms.Linux)]
NegotiateStream_StreamToStream_NtlmAuthentication_NtlmUser_InvalidCredentials_Fail(NetworkCredential credential)749         public void NegotiateStream_StreamToStream_NtlmAuthentication_NtlmUser_InvalidCredentials_Fail(NetworkCredential credential)
750         {
751             if (!_isNtlmAvailable)
752             {
753                 _output.WriteLine("skipping NegotiateStream_StreamToStream_NtlmAuthentication_NtlmUser_InvalidCredentials_Fail");
754                 return;
755             }
756 
757             VirtualNetwork network = new VirtualNetwork();
758             using (var clientStream = new VirtualNetworkStream(network, isServer: false))
759             using (var serverStream = new VirtualNetworkStream(network, isServer: true))
760             using (var client = new NegotiateStream(clientStream))
761             using (var server = new UnixGssFakeNegotiateStream(serverStream))
762             {
763                 Assert.False(client.IsAuthenticated, "client.IsAuthenticated");
764                 Assert.ThrowsAsync<AuthenticationException>(() => server.AuthenticateAsServerAsync());
765                 Assert.ThrowsAsync<AuthenticationException>(() => client.AuthenticateAsClientAsync(credential, _testTarget, ProtectionLevel.None, TokenImpersonationLevel.Identification));
766             }
767         }
768 
Dispose()769         public void Dispose()
770         {
771             try
772             {
773                 _fixture.CheckAndClearCredentials(_output);
774             }
775             catch
776             {
777             }
778         }
779     }
780 }
781