From b5e15dce8b07dfea00917871d7978db27eafd68d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Sep 2021 10:45:55 -0700 Subject: [PATCH] [release/6.0] fix SendAsync from impersonificated context with default credentials (#59155) * fix SendAsync from inpersonificated context and default credentials * add missing file * remove dead code * feedback from review * name cleanup Co-authored-by: wfurt --- .../Common/tests/System/Net/Http/LoopbackServer.cs | 6 + .../TestUtilities/System/WindowsIdentityFixture.cs | 141 +++++++++++++++++++ .../tests/TestUtilities/TestUtilities.csproj | 1 + .../SocketsHttpHandler/HttpConnectionSettings.cs | 6 +- .../tests/FunctionalTests/ImpersonatedAuthTests.cs | 94 +++++++++++++ .../tests/FunctionalTests/NtAuthTests.Windows.cs | 153 +++++++++++++++++++++ .../tests/FunctionalTests/NtAuthTests.cs | 2 +- .../System.Net.Http.Functional.Tests.csproj | 110 ++++++++++++++- .../WindowsIdentityImpersonatedTests.netcoreapp.cs | 129 +---------------- 9 files changed, 508 insertions(+), 134 deletions(-) create mode 100644 src/libraries/Common/tests/TestUtilities/System/WindowsIdentityFixture.cs create mode 100644 src/libraries/System.Net.Http/tests/FunctionalTests/ImpersonatedAuthTests.cs create mode 100644 src/libraries/System.Net.Http/tests/FunctionalTests/NtAuthTests.Windows.cs diff --git a/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs index 7594b49..ff4b346 100644 --- a/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs +++ b/src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs @@ -866,6 +866,12 @@ namespace System.Net.Test.Common return buffer; } + public void CompleteRequestProcessing() + { + _contentLength = 0; + _bodyRead = false; + } + public override async Task SendResponseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList headers = null, string content = "", bool isFinal = true, int requestId = 0) { MemoryStream headerBytes = new MemoryStream(); diff --git a/src/libraries/Common/tests/TestUtilities/System/WindowsIdentityFixture.cs b/src/libraries/Common/tests/TestUtilities/System/WindowsIdentityFixture.cs new file mode 100644 index 0000000..360fbe6 --- /dev/null +++ b/src/libraries/Common/tests/TestUtilities/System/WindowsIdentityFixture.cs @@ -0,0 +1,141 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.ComponentModel; +using System.Linq; +using System.Net; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Security.Principal; +using System.Threading.Tasks; +using Microsoft.Win32.SafeHandles; + +namespace System +{ + public class WindowsIdentityFixture : IDisposable + { + public WindowsTestAccount TestAccount { get; private set; } + + public WindowsIdentityFixture() + { + TestAccount = new WindowsTestAccount("CorFxTstWiIde01kiu"); + } + + public void Dispose() + { + TestAccount.Dispose(); + } + } + + public sealed class WindowsTestAccount : IDisposable + { + private readonly string _userName; + private SafeAccessTokenHandle _accountTokenHandle; + public SafeAccessTokenHandle AccountTokenHandle => _accountTokenHandle; + public string AccountName { get; private set; } + + public WindowsTestAccount(string userName) + { + _userName = userName; + CreateUser(); + } + + private void CreateUser() + { + string testAccountPassword; + using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) + { + byte[] randomBytes = new byte[33]; + rng.GetBytes(randomBytes); + + // Add special chars to ensure it satisfies password requirements. + testAccountPassword = Convert.ToBase64String(randomBytes) + "_-As@!%*(1)4#2"; + + USER_INFO_1 userInfo = new USER_INFO_1 + { + usri1_name = _userName, + usri1_password = testAccountPassword, + usri1_priv = 1 + }; + + // Create user and remove/create if already exists + uint result = NetUserAdd(null, 1, ref userInfo, out uint param_err); + + // error codes https://docs.microsoft.com/en-us/windows/desktop/netmgmt/network-management-error-codes + // 0 == NERR_Success + if (result == 2224) // NERR_UserExists + { + result = NetUserDel(null, userInfo.usri1_name); + if (result != 0) + { + throw new Win32Exception((int)result); + } + result = NetUserAdd(null, 1, ref userInfo, out param_err); + if (result != 0) + { + throw new Win32Exception((int)result); + } + } + + const int LOGON32_PROVIDER_DEFAULT = 0; + const int LOGON32_LOGON_INTERACTIVE = 2; + + if (!LogonUser(_userName, ".", testAccountPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out _accountTokenHandle)) + { + _accountTokenHandle = null; + throw new Exception($"Failed to get SafeAccessTokenHandle for test account {_userName}", new Win32Exception()); + } + + bool gotRef = false; + try + { + _accountTokenHandle.DangerousAddRef(ref gotRef); + IntPtr logonToken = _accountTokenHandle.DangerousGetHandle(); + AccountName = new WindowsIdentity(logonToken).Name; + } + finally + { + if (gotRef) + _accountTokenHandle.DangerousRelease(); + } + } + } + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern bool LogonUser(string userName, string domain, string password, int logonType, int logonProvider, out SafeAccessTokenHandle safeAccessTokenHandle); + + [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern uint NetUserAdd([MarshalAs(UnmanagedType.LPWStr)]string servername, uint level, ref USER_INFO_1 buf, out uint parm_err); + + [DllImport("netapi32.dll")] + internal static extern uint NetUserDel([MarshalAs(UnmanagedType.LPWStr)]string servername, [MarshalAs(UnmanagedType.LPWStr)]string username); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct USER_INFO_1 + { + public string usri1_name; + public string usri1_password; + public uint usri1_password_age; + public uint usri1_priv; + public string usri1_home_dir; + public string usri1_comment; + public uint usri1_flags; + public string usri1_script_path; + } + + public void Dispose() + { + _accountTokenHandle?.Dispose(); + + uint result = NetUserDel(null, _userName); + + // 2221= NERR_UserNotFound + if (result != 0 && result != 2221) + { + throw new Win32Exception((int)result); + } + } + } + } + diff --git a/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj b/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj index 375fca4..adf4da7 100644 --- a/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj +++ b/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj @@ -33,6 +33,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Security.Principal.Windows/tests/WindowsIdentityImpersonatedTests.netcoreapp.cs b/src/libraries/System.Security.Principal.Windows/tests/WindowsIdentityImpersonatedTests.netcoreapp.cs index 868afcc..4bfb059d 100644 --- a/src/libraries/System.Security.Principal.Windows/tests/WindowsIdentityImpersonatedTests.netcoreapp.cs +++ b/src/libraries/System.Security.Principal.Windows/tests/WindowsIdentityImpersonatedTests.netcoreapp.cs @@ -84,6 +84,9 @@ public class WindowsIdentityImpersonatedTests : IClassFixture { Assert.Equal(_fixture.TestAccount.AccountName, WindowsIdentity.GetCurrent().Name); @@ -96,129 +99,3 @@ public class WindowsIdentityImpersonatedTests : IClassFixture _accountTokenHandle; - public string AccountName { get; private set; } - - public WindowsTestAccount(string userName) - { - _userName = userName; - CreateUser(); - } - - private void CreateUser() - { - string testAccountPassword; - using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) - { - byte[] randomBytes = new byte[33]; - rng.GetBytes(randomBytes); - - // Add special chars to ensure it satisfies password requirements. - testAccountPassword = Convert.ToBase64String(randomBytes) + "_-As@!%*(1)4#2"; - - USER_INFO_1 userInfo = new USER_INFO_1 - { - usri1_name = _userName, - usri1_password = testAccountPassword, - usri1_priv = 1 - }; - - // Create user and remove/create if already exists - uint result = NetUserAdd(null, 1, ref userInfo, out uint param_err); - - // error codes https://docs.microsoft.com/en-us/windows/desktop/netmgmt/network-management-error-codes - // 0 == NERR_Success - if (result == 2224) // NERR_UserExists - { - result = NetUserDel(null, userInfo.usri1_name); - if (result != 0) - { - throw new Win32Exception((int)result); - } - result = NetUserAdd(null, 1, ref userInfo, out param_err); - if (result != 0) - { - throw new Win32Exception((int)result); - } - } - - const int LOGON32_PROVIDER_DEFAULT = 0; - const int LOGON32_LOGON_INTERACTIVE = 2; - - if (!LogonUser(_userName, ".", testAccountPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out _accountTokenHandle)) - { - _accountTokenHandle = null; - throw new Exception($"Failed to get SafeAccessTokenHandle for test account {_userName}", new Win32Exception()); - } - - bool gotRef = false; - try - { - _accountTokenHandle.DangerousAddRef(ref gotRef); - IntPtr logonToken = _accountTokenHandle.DangerousGetHandle(); - AccountName = new WindowsIdentity(logonToken).Name; - } - finally - { - if (gotRef) - _accountTokenHandle.DangerousRelease(); - } - } - } - - [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern bool LogonUser(string userName, string domain, string password, int logonType, int logonProvider, out SafeAccessTokenHandle safeAccessTokenHandle); - - [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern uint NetUserAdd([MarshalAs(UnmanagedType.LPWStr)]string servername, uint level, ref USER_INFO_1 buf, out uint parm_err); - - [DllImport("netapi32.dll")] - internal static extern uint NetUserDel([MarshalAs(UnmanagedType.LPWStr)]string servername, [MarshalAs(UnmanagedType.LPWStr)]string username); - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct USER_INFO_1 - { - public string usri1_name; - public string usri1_password; - public uint usri1_password_age; - public uint usri1_priv; - public string usri1_home_dir; - public string usri1_comment; - public uint usri1_flags; - public string usri1_script_path; - } - - public void Dispose() - { - _accountTokenHandle?.Dispose(); - - uint result = NetUserDel(null, _userName); - - // 2221= NERR_UserNotFound - if (result != 0 && result != 2221) - { - throw new Win32Exception((int)result); - } - } -} - -- 2.7.4