From 83b224c255602199989450e1376b5c549e9e1182 Mon Sep 17 00:00:00 2001 From: Luca Leonardo Scorcia Date: Thu, 17 Feb 2022 04:00:24 -0500 Subject: [PATCH 1/8] Fix #41618 Correct marshalling of SortKey objects on Linux --- .../System.DirectoryServices.Protocols.csproj | 2 ++ .../Protocols/Interop/SortKey.Linux.cs | 18 ++++++++++++++++++ .../Protocols/Interop/SortKey.Windows.cs | 18 ++++++++++++++++++ .../Protocols/common/DirectoryControl.cs | 5 +++-- 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Linux.cs create mode 100644 src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj index 43c120b0a74a09..ba1d7b383f15bd 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj +++ b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj @@ -58,6 +58,7 @@ + @@ -76,6 +77,7 @@ + diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Linux.cs new file mode 100644 index 00000000000000..21d2063e61873d --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Linux.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.ComponentModel; +using System.Diagnostics; +using System.Text; +using System.Runtime.InteropServices; +using System.Security.Principal; +using System.Runtime.Versioning; + +namespace System.DirectoryServices.Protocols +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public partial class SortKey + { + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs new file mode 100644 index 00000000000000..f18b4d4b1bc788 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.ComponentModel; +using System.Diagnostics; +using System.Text; +using System.Runtime.InteropServices; +using System.Security.Principal; +using System.Runtime.Versioning; + +namespace System.DirectoryServices.Protocols +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public partial class SortKey + { + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs index bdef26646fedb6..786bb69b59ebbb 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs @@ -50,8 +50,9 @@ internal static class UtilityHandle public static ConnectionHandle GetHandle() => s_handle; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public class SortKey + // This class is marked partial to allow customization of the + // marshalling attribute on different platforms + public partial class SortKey { private string _name; private string _rule; From 9fa6938fd4fc96cda26c195a96d2b0706d8370ac Mon Sep 17 00:00:00 2001 From: Luca Leonardo Scorcia Date: Fri, 18 Feb 2022 04:45:36 -0500 Subject: [PATCH 2/8] Correct the test expectation for OpenLdap platforms --- .../tests/SortRequestControlTests.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/SortRequestControlTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/SortRequestControlTests.cs index 26bc2ca73f17d3..480b537bab85b6 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/SortRequestControlTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/SortRequestControlTests.cs @@ -32,11 +32,15 @@ public void Ctor_SortKeys(bool critical) control.IsCritical = critical; var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? + // WLDAP formatted ASN.1 new byte[] { 48, 132, 0, 0, 0, 43, 48, 132, 0, 0, 0, 17, 4, 5,110, 97, 109, 101, 49, 128, 5, 114, 117, 108, 101, 49, 129, 1, 255, 48, 132, 0, 0, 0, 14, 4, 5, 110, 97, 109, 101, - 50, 128, 5, 114, 117, 108, 101, 50} : - new byte[] { 48, 19, 48, 9, 4, 1, 110, 128, 1, 114, 129, 1, 255, 48, 6, 4, 1, 110, 128, 1, 114 }; + 50, 128, 5, 114, 117, 108, 101, 50 } : + // OpenLdap formatted ASN.1 + new byte[] { 48, 35, 48, 17, 4, 5, 110, 97, 109, 101, 49, 128, 5, + 114, 117, 108, 101, 49, 129, 1, 255, 48, 14, 4, 5, 110, 97, 109, + 101, 50, 128, 5, 114, 117, 108, 101, 50 }; Assert.Equal(expected, control.GetValue()); } From 2493b9503ba3d1db2ca7ff958a8400d40a9fd287 Mon Sep 17 00:00:00 2001 From: Luca Leonardo Scorcia Date: Tue, 1 Mar 2022 03:27:40 -0500 Subject: [PATCH 3/8] Add test for LDAP sort control against a real LDAP server --- .../tests/DirectoryServicesProtocolsTests.cs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs index f13a864d000187..b3be076bc9bc88 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs @@ -533,6 +533,58 @@ public void TestPageRequests() } } + [ConditionalFact(nameof(IsLdapConfigurationExist))] + public void TestSortedSearch() + { + using (LdapConnection connection = GetConnection()) + { + string ouName = "ProtocolsGroup10"; + string dn = "ou=" + ouName; + + try + { + for (int i=0; i<10; i++) + { + DeleteEntry(connection, "ou=ProtocolsSubGroup10." + i + "," + dn); + } + DeleteEntry(connection, dn); + + AddOrganizationalUnit(connection, dn); + SearchResultEntry sre = SearchOrganizationalUnit(connection, LdapConfiguration.Configuration.SearchDn, ouName); + Assert.NotNull(sre); + + for (int i=0; i<10; i++) + { + AddOrganizationalUnit(connection, "ou=ProtocolsSubGroup10." + i + "," + dn); + } + + string filter = "(objectClass=*)"; + SearchRequest searchRequest = new SearchRequest( + dn + "," + LdapConfiguration.Configuration.SearchDn, + filter, + SearchScope.Subtree, + null); + + var sortRequestControl = new SortRequestControl("ou", true); + searchRequest.Controls.Add(sortRequestControl); + + SearchResponse searchResponse = (SearchResponse) connection.SendRequest(searchRequest); + Assert.Equal(1, searchResponse.Controls.Length); + Assert.True(searchResponse.Controls[0] is SortResponseControl); + Assert.True(searchResponse.Entries.Count > 0); + Assert.Equal("ou=ProtocolsSubGroup10.9," + dn + "," + LdapConfiguration.Configuration.SearchDn, searchResponse.Entries[0].DistinguishedName); + } + finally + { + for (int i=0; i<20; i++) + { + DeleteEntry(connection, "ou=ProtocolsSubGroup10." + i + "," + dn); + } + DeleteEntry(connection, dn); + } + } + } + private void DeleteAttribute(LdapConnection connection, string entryDn, string attributeName) { string dn = entryDn + "," + LdapConfiguration.Configuration.SearchDn; From 11ba0242a5d8c75f97b1ea7f8088acffa43f4474 Mon Sep 17 00:00:00 2001 From: Luca Leonardo Scorcia Date: Fri, 4 Mar 2022 03:52:08 -0500 Subject: [PATCH 4/8] Introduce SortKeyInterop class and restore original SortKey definition --- .../Protocols/Interop/SortKey.Linux.cs | 34 ++++++++++++++++++- .../Protocols/Interop/SortKey.Windows.cs | 34 ++++++++++++++++++- .../Protocols/common/DirectoryControl.cs | 17 ++++++---- 3 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Linux.cs index 21d2063e61873d..272a4e1d284841 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Linux.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Linux.cs @@ -12,7 +12,39 @@ namespace System.DirectoryServices.Protocols { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public partial class SortKey + internal class SortKeyInterop { + private string _name; + private string _rule; + private bool _order; + + public SortKeyInterop() + { + } + + public SortKeyInterop(string attributeName, string matchingRule, bool reverseOrder) + { + AttributeName = attributeName; + _rule = matchingRule; + _order = reverseOrder; + } + + public string AttributeName + { + get => _name; + set => _name = value ?? throw new ArgumentNullException(nameof(value)); + } + + public string MatchingRule + { + get => _rule; + set => _rule = value; + } + + public bool ReverseOrder + { + get => _order; + set => _order = value; + } } } diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs index f18b4d4b1bc788..ca95c8c15e53cb 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs @@ -12,7 +12,39 @@ namespace System.DirectoryServices.Protocols { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public partial class SortKey + internal class SortKeyInterop { + private string _name; + private string _rule; + private bool _order; + + public SortKeyInterop() + { + } + + public SortKeyInterop(string attributeName, string matchingRule, bool reverseOrder) + { + AttributeName = attributeName; + _rule = matchingRule; + _order = reverseOrder; + } + + public string AttributeName + { + get => _name; + set => _name = value ?? throw new ArgumentNullException(nameof(value)); + } + + public string MatchingRule + { + get => _rule; + set => _rule = value; + } + + public bool ReverseOrder + { + get => _order; + set => _order = value; + } } } diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs index 786bb69b59ebbb..0eae8bf6f26a74 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs @@ -50,9 +50,7 @@ internal static class UtilityHandle public static ConnectionHandle GetHandle() => s_handle; } - // This class is marked partial to allow customization of the - // marshalling attribute on different platforms - public partial class SortKey + public class SortKey { private string _name; private string _rule; @@ -704,9 +702,16 @@ public SortKey[] SortKeys public override byte[] GetValue() { + SortKeyInterop[] nativeSortKeys = new SortKeyInterop[_keys.Length]; + for (int i = 0; i < _keys.Length; ++i) + { + nativeSortKeys[i] = new SortKeyInterop(_keys[i].AttributeName, + _keys[i].MatchingRule, _keys[i].ReverseOrder); + } + IntPtr control = IntPtr.Zero; - int structSize = Marshal.SizeOf(typeof(SortKey)); - int keyCount = _keys.Length; + int structSize = Marshal.SizeOf(typeof(SortKeyInterop)); + int keyCount = nativeSortKeys.Length; IntPtr memHandle = Utility.AllocHGlobalIntPtrArray(keyCount + 1); try @@ -717,7 +722,7 @@ public override byte[] GetValue() for (i = 0; i < keyCount; i++) { sortPtr = Marshal.AllocHGlobal(structSize); - Marshal.StructureToPtr(_keys[i], sortPtr, false); + Marshal.StructureToPtr(nativeSortKeys[i], sortPtr, false); tempPtr = (IntPtr)((long)memHandle + IntPtr.Size * i); Marshal.WriteIntPtr(tempPtr, sortPtr); } From c1bfb541c4fe3b287027d918959c05ce200d846f Mon Sep 17 00:00:00 2001 From: Luca Leonardo Scorcia Date: Fri, 4 Mar 2022 16:57:03 -0500 Subject: [PATCH 5/8] Reduce duplication and make SortKeyInterop a struct --- .../System.DirectoryServices.Protocols.csproj | 5 +- .../Protocols/Interop/SortKey.Windows.cs | 50 ------------------- .../Protocols/Interop/SortKeyInterop.Linux.cs | 18 +++++++ .../Interop/SortKeyInterop.Windows.cs | 18 +++++++ .../{SortKey.Linux.cs => SortKeyInterop.cs} | 18 +++---- .../Protocols/common/DirectoryControl.cs | 3 +- 6 files changed, 48 insertions(+), 64 deletions(-) delete mode 100644 src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs create mode 100644 src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.Linux.cs create mode 100644 src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.Windows.cs rename src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/{SortKey.Linux.cs => SortKeyInterop.cs} (65%) diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj index ba1d7b383f15bd..33bfe13efee4e1 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj +++ b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj @@ -42,6 +42,7 @@ + Common\DisableRuntimeMarshalling.cs @@ -58,7 +59,7 @@ - + @@ -77,7 +78,7 @@ - + diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs deleted file mode 100644 index ca95c8c15e53cb..00000000000000 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Windows.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections; -using System.ComponentModel; -using System.Diagnostics; -using System.Text; -using System.Runtime.InteropServices; -using System.Security.Principal; -using System.Runtime.Versioning; - -namespace System.DirectoryServices.Protocols -{ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal class SortKeyInterop - { - private string _name; - private string _rule; - private bool _order; - - public SortKeyInterop() - { - } - - public SortKeyInterop(string attributeName, string matchingRule, bool reverseOrder) - { - AttributeName = attributeName; - _rule = matchingRule; - _order = reverseOrder; - } - - public string AttributeName - { - get => _name; - set => _name = value ?? throw new ArgumentNullException(nameof(value)); - } - - public string MatchingRule - { - get => _rule; - set => _rule = value; - } - - public bool ReverseOrder - { - get => _order; - set => _order = value; - } - } -} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.Linux.cs new file mode 100644 index 00000000000000..6119ae0956500f --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.Linux.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.ComponentModel; +using System.Diagnostics; +using System.Text; +using System.Runtime.InteropServices; +using System.Security.Principal; +using System.Runtime.Versioning; + +namespace System.DirectoryServices.Protocols +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal partial struct SortKeyInterop + { + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.Windows.cs new file mode 100644 index 00000000000000..42ada55602cc65 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.Windows.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.ComponentModel; +using System.Diagnostics; +using System.Text; +using System.Runtime.InteropServices; +using System.Security.Principal; +using System.Runtime.Versioning; + +namespace System.DirectoryServices.Protocols +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal partial struct SortKeyInterop + { + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.cs similarity index 65% rename from src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Linux.cs rename to src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.cs index 272a4e1d284841..57b199f97893e5 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKey.Linux.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.cs @@ -11,28 +11,26 @@ namespace System.DirectoryServices.Protocols { - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class SortKeyInterop + internal partial struct SortKeyInterop { private string _name; private string _rule; private bool _order; - public SortKeyInterop() + public SortKeyInterop(SortKey sortKey) { - } + if (sortKey == null) + throw new ArgumentNullException(nameof(sortKey)); - public SortKeyInterop(string attributeName, string matchingRule, bool reverseOrder) - { - AttributeName = attributeName; - _rule = matchingRule; - _order = reverseOrder; + _name = sortKey.AttributeName; + _rule = sortKey.MatchingRule; + _order = sortKey.ReverseOrder; } public string AttributeName { get => _name; - set => _name = value ?? throw new ArgumentNullException(nameof(value)); + set => _name = value; } public string MatchingRule diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs index 0eae8bf6f26a74..e98c73b0d9a88b 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs @@ -705,8 +705,7 @@ public override byte[] GetValue() SortKeyInterop[] nativeSortKeys = new SortKeyInterop[_keys.Length]; for (int i = 0; i < _keys.Length; ++i) { - nativeSortKeys[i] = new SortKeyInterop(_keys[i].AttributeName, - _keys[i].MatchingRule, _keys[i].ReverseOrder); + nativeSortKeys[i] = new SortKeyInterop(_keys[i]); } IntPtr control = IntPtr.Zero; From 97c7c67bbb8830c036e00443bc2f8b23ccde67e7 Mon Sep 17 00:00:00 2001 From: Luca Leonardo Scorcia Date: Thu, 10 Mar 2022 02:25:25 -0500 Subject: [PATCH 6/8] Code style improvements --- .../Protocols/Interop/SortKeyInterop.cs | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.cs index 57b199f97893e5..b3585792faefab 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.cs @@ -11,38 +11,24 @@ namespace System.DirectoryServices.Protocols { + // Declared as partial in order to be able to set the different StructLayout + // attributes in the Windows and Linux specific files. internal partial struct SortKeyInterop { - private string _name; - private string _rule; - private bool _order; - public SortKeyInterop(SortKey sortKey) { if (sortKey == null) throw new ArgumentNullException(nameof(sortKey)); - _name = sortKey.AttributeName; - _rule = sortKey.MatchingRule; - _order = sortKey.ReverseOrder; + AttributeName = sortKey.AttributeName; + MatchingRule = sortKey.MatchingRule; + ReverseOrder = sortKey.ReverseOrder; } - public string AttributeName - { - get => _name; - set => _name = value; - } + public string AttributeName { get; set; } - public string MatchingRule - { - get => _rule; - set => _rule = value; - } + public string MatchingRule { get; set; } - public bool ReverseOrder - { - get => _order; - set => _order = value; - } + public bool ReverseOrder { get; set; } } } From 76029df42e9677711df9f363fbe9b5906a41c9ce Mon Sep 17 00:00:00 2001 From: Luca Leonardo Scorcia Date: Tue, 15 Mar 2022 03:56:28 -0400 Subject: [PATCH 7/8] Reintroduce StructLayout attribute on SortKey class --- .../DirectoryServices/Protocols/Interop/SortKeyInterop.cs | 7 ++++--- .../DirectoryServices/Protocols/common/DirectoryControl.cs | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.cs index b3585792faefab..29ceb3a005522b 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SortKeyInterop.cs @@ -13,6 +13,7 @@ namespace System.DirectoryServices.Protocols { // Declared as partial in order to be able to set the different StructLayout // attributes in the Windows and Linux specific files. + // This is a layout-controlled struct, do not alter property ordering. internal partial struct SortKeyInterop { public SortKeyInterop(SortKey sortKey) @@ -25,10 +26,10 @@ public SortKeyInterop(SortKey sortKey) ReverseOrder = sortKey.ReverseOrder; } - public string AttributeName { get; set; } + internal string AttributeName { get; set; } - public string MatchingRule { get; set; } + internal string MatchingRule { get; set; } - public bool ReverseOrder { get; set; } + internal bool ReverseOrder { get; set; } } } diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs index e98c73b0d9a88b..6592f09945136d 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs @@ -50,6 +50,7 @@ internal static class UtilityHandle public static ConnectionHandle GetHandle() => s_handle; } + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public class SortKey { private string _name; From 27d87a98a307b438a0b352bf19a0f8b6a0ed3775 Mon Sep 17 00:00:00 2001 From: Luca Leonardo Scorcia Date: Wed, 16 Mar 2022 16:56:22 -0400 Subject: [PATCH 8/8] Conditionally enable Sort Control tests for OpenDJ and Active Directory only --- .../System/DirectoryServices/LDAP.Configuration.xml | 4 ++++ .../System/DirectoryServices/LdapConfiguration.cs | 13 +++++++++++-- .../tests/DirectoryServicesProtocolsTests.cs | 4 +++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml b/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml index 24e41ecd4e7ea5..3580fab4ecfe6f 100644 --- a/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml +++ b/src/libraries/Common/tests/System/DirectoryServices/LDAP.Configuration.xml @@ -94,6 +94,7 @@ Note: cn=admin,dc=example,dc=com password ServerBind,None + True localhost @@ -102,6 +103,7 @@ Note: cn=admin,dc=example,dc=com password ServerBind,None + False danmose-ldap.danmose-domain.com @@ -110,6 +112,7 @@ Note: danmose-domain\Administrator %TESTPASSWORD% ServerBind,None + True ldap.local @@ -119,6 +122,7 @@ Note: password ServerBind,None true + False \ No newline at end of file diff --git a/src/libraries/Common/tests/System/DirectoryServices/LdapConfiguration.cs b/src/libraries/Common/tests/System/DirectoryServices/LdapConfiguration.cs index a9156b8efd5bbe..beed82aabcfa62 100644 --- a/src/libraries/Common/tests/System/DirectoryServices/LdapConfiguration.cs +++ b/src/libraries/Common/tests/System/DirectoryServices/LdapConfiguration.cs @@ -10,7 +10,7 @@ namespace System.DirectoryServices.Tests { internal class LdapConfiguration { - private LdapConfiguration(string serverName, string searchDn, string userName, string password, string port, AuthenticationTypes at, bool useTls) + private LdapConfiguration(string serverName, string searchDn, string userName, string password, string port, AuthenticationTypes at, bool useTls, bool supportsServerSideSort) { ServerName = serverName; SearchDn = searchDn; @@ -19,6 +19,7 @@ private LdapConfiguration(string serverName, string searchDn, string userName, s Port = port; AuthenticationTypes = at; UseTls = useTls; + SupportsServerSideSort = supportsServerSideSort; } private static LdapConfiguration s_ldapConfiguration = GetConfiguration("LDAP.Configuration.xml"); @@ -32,6 +33,7 @@ private LdapConfiguration(string serverName, string searchDn, string userName, s internal string SearchDn { get; set; } internal AuthenticationTypes AuthenticationTypes { get; set; } internal bool UseTls { get; set; } + internal bool SupportsServerSideSort { get; set; } internal string LdapPath => string.IsNullOrEmpty(Port) ? $"LDAP://{ServerName}/{SearchDn}" : $"LDAP://{ServerName}:{Port}/{SearchDn}"; internal string RootDSEPath => string.IsNullOrEmpty(Port) ? $"LDAP://{ServerName}/rootDSE" : $"LDAP://{ServerName}:{Port}/rootDSE"; internal string UserNameWithNoDomain @@ -107,6 +109,7 @@ internal static LdapConfiguration GetConfiguration(string configFile) string password = ""; AuthenticationTypes at = AuthenticationTypes.None; bool useTls = false; + bool supportsServerSideSort = false; XElement child = connection.Element("ServerName"); if (child != null) @@ -141,6 +144,12 @@ internal static LdapConfiguration GetConfiguration(string configFile) useTls = bool.Parse(child.Value); } + child = connection.Element("SupportsServerSideSort"); + if (child != null) + { + supportsServerSideSort = bool.Parse(child.Value); + } + child = connection.Element("AuthenticationTypes"); if (child != null) { @@ -170,7 +179,7 @@ internal static LdapConfiguration GetConfiguration(string configFile) at |= AuthenticationTypes.Signing; } - ldapConfig = new LdapConfiguration(serverName, searchDn, user, password, port, at, useTls); + ldapConfig = new LdapConfiguration(serverName, searchDn, user, password, port, at, useTls, supportsServerSideSort); } } catch (Exception ex) diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs index b3be076bc9bc88..5e2356366ddc83 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs @@ -15,6 +15,8 @@ public partial class DirectoryServicesProtocolsTests internal static bool IsLdapConfigurationExist => LdapConfiguration.Configuration != null; internal static bool IsActiveDirectoryServer => IsLdapConfigurationExist && LdapConfiguration.Configuration.IsActiveDirectoryServer; + internal static bool IsServerSideSortSupported => IsLdapConfigurationExist && LdapConfiguration.Configuration.SupportsServerSideSort; + [ConditionalFact(nameof(IsLdapConfigurationExist))] public void TestInvalidFilter() { @@ -533,7 +535,7 @@ public void TestPageRequests() } } - [ConditionalFact(nameof(IsLdapConfigurationExist))] + [ConditionalFact(nameof(IsServerSideSortSupported))] public void TestSortedSearch() { using (LdapConnection connection = GetConnection())