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