diff --git a/src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs b/src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs index e99d957778808..45dc7c9325a47 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs @@ -71,13 +71,19 @@ private static string GetGssApiDisplayStatus(Status majorStatus, Status minorSta private static string? GetGssApiDisplayStatus(Status status, bool isMinor) { + if (!System.Net.NegotiateAuthenticationPal.HasSystemNetSecurityNative) + { + // avoid calling into libSystem.Net.Security.Native. + return null; + } + GssBuffer displayBuffer = default(GssBuffer); try { Interop.NetSecurityNative.Status minStat; Interop.NetSecurityNative.Status displayCallStatus = isMinor ? - DisplayMinorStatus(out minStat, status, ref displayBuffer): + DisplayMinorStatus(out minStat, status, ref displayBuffer) : DisplayMajorStatus(out minStat, status, ref displayBuffer); return (Status.GSS_S_COMPLETE != displayCallStatus) ? null : Marshal.PtrToStringUTF8(displayBuffer._data); } diff --git a/src/libraries/Common/tests/System/Net/Capability.Security.Unix.cs b/src/libraries/Common/tests/System/Net/Capability.Security.Unix.cs index 3e08ee08a837a..bad2ddd2dd73f 100644 --- a/src/libraries/Common/tests/System/Net/Capability.Security.Unix.cs +++ b/src/libraries/Common/tests/System/Net/Capability.Security.Unix.cs @@ -1,15 +1,20 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.InteropServices; + namespace System.Net.Test.Common { public static partial class Capability { public static bool IsNtlmInstalled() { - // GSS on Linux does not work with OpenSSL 3.0. Fix was submitted to gss-ntlm but it will take a while to make to - // all supported distributions. The second part of the check should be removed when it does. - return Interop.NetSecurityNative.IsNtlmInstalled() && (!PlatformDetection.IsOpenSslSupported || PlatformDetection.OpenSslVersion.Major < 3); + return + // Linux bionic uses managed NTLM implementation + (OperatingSystem.IsLinux() && RuntimeInformation.RuntimeIdentifier.StartsWith("linux-bionic-", StringComparison.Ordinal)) || + // GSS on Linux does not work with OpenSSL 3.0. Fix was submitted to gss-ntlm but it will take a while to make to + // all supported distributions. The second part of the check should be removed when it does. + Interop.NetSecurityNative.IsNtlmInstalled() && (!PlatformDetection.IsOpenSslSupported || PlatformDetection.OpenSslVersion.Major < 3); } } } diff --git a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs index f200e11ca4c43..d3b39321b12bf 100644 --- a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs +++ b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs @@ -19,10 +19,13 @@ namespace System.Net { internal partial class NegotiateAuthenticationPal { + private static readonly Lazy _hasSystemNetSecurityNative = new Lazy(CheckHasSystemNetSecurityNative); + internal static bool HasSystemNetSecurityNative => _hasSystemNetSecurityNative.Value; private static bool UseManagedNtlm { get; } = AppContext.TryGetSwitch("System.Net.Security.UseManagedNtlm", out bool useManagedNtlm) ? useManagedNtlm : - OperatingSystem.IsMacOS() || OperatingSystem.IsIOS() || OperatingSystem.IsMacCatalyst(); + OperatingSystem.IsMacOS() || OperatingSystem.IsIOS() || OperatingSystem.IsMacCatalyst() || + (OperatingSystem.IsLinux() && RuntimeInformation.RuntimeIdentifier.StartsWith("linux-bionic-", StringComparison.OrdinalIgnoreCase)); public static NegotiateAuthenticationPal Create(NegotiateAuthenticationClientOptions clientOptions) { @@ -34,7 +37,7 @@ public static NegotiateAuthenticationPal Create(NegotiateAuthenticationClientOpt return ManagedNtlmNegotiateAuthenticationPal.Create(clientOptions); case NegotiationInfoClass.Negotiate: - return new ManagedSpnegoNegotiateAuthenticationPal(clientOptions, supportKerberos: true); + return new ManagedSpnegoNegotiateAuthenticationPal(clientOptions, supportKerberos: HasSystemNetSecurityNative); } } @@ -559,7 +562,8 @@ private NegotiateAuthenticationStatusCode InitializeSecurityContext( { if (NetEventSource.Log.IsEnabled()) { - string protocol = _packageType switch { + string protocol = _packageType switch + { Interop.NetSecurityNative.PackageType.NTLM => "NTLM", Interop.NetSecurityNative.PackageType.Kerberos => "Kerberos", _ => "SPNEGO" @@ -635,7 +639,8 @@ private NegotiateAuthenticationStatusCode InitializeSecurityContext( { if (NetEventSource.Log.IsEnabled()) { - string protocol = _packageType switch { + string protocol = _packageType switch + { Interop.NetSecurityNative.PackageType.NTLM => "NTLM", Interop.NetSecurityNative.PackageType.Kerberos => "Kerberos", _ => isNtlmUsed ? "SPNEGO-NTLM" : "SPNEGO-Kerberos" @@ -764,5 +769,18 @@ internal static NegotiateAuthenticationStatusCode GetErrorCode(Interop.NetSecuri } } } + + public static bool CheckHasSystemNetSecurityNative() + { + try + { + return Interop.NetSecurityNative.IsNtlmInstalled(); + } + catch (Exception e) when (e is EntryPointNotFoundException || e is DllNotFoundException || e is TypeInitializationException) + { + // libSystem.Net.Security.Native is not available + return false; + } + } } } diff --git a/src/libraries/System.Net.Security/tests/UnitTests/NegotiateAuthenticationTests.cs b/src/libraries/System.Net.Security/tests/UnitTests/NegotiateAuthenticationTests.cs index e2a092ba5e7af..56d86c06b51e2 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/NegotiateAuthenticationTests.cs +++ b/src/libraries/System.Net.Security/tests/UnitTests/NegotiateAuthenticationTests.cs @@ -32,7 +32,6 @@ public void Constructor_Overloads_Validation() } [Fact] - [SkipOnPlatform(TestPlatforms.LinuxBionic, "https://github.com/dotnet/runtime/issues/93104")] public void RemoteIdentity_ThrowsOnUnauthenticated() { NegotiateAuthenticationClientOptions clientOptions = new NegotiateAuthenticationClientOptions { Credential = s_testCredentialRight, TargetName = "HTTP/foo" }; @@ -66,7 +65,6 @@ public void RemoteIdentity_ThrowsOnDisposed() } [Fact] - [SkipOnPlatform(TestPlatforms.LinuxBionic, "https://github.com/dotnet/runtime/issues/93104")] public void Package_Unsupported() { NegotiateAuthenticationClientOptions clientOptions = new NegotiateAuthenticationClientOptions { Package = "INVALID", Credential = s_testCredentialRight, TargetName = "HTTP/foo" }; @@ -98,7 +96,6 @@ public void Package_Unsupported_NTLM() [Fact] [SkipOnPlatform(TestPlatforms.Windows, "The test is specific to GSSAPI / Managed implementations of NegotiateAuthentication")] - [SkipOnPlatform(TestPlatforms.LinuxBionic, "https://github.com/dotnet/runtime/issues/93104")] public void DefaultNetworkCredentials_NTLM_DoesNotThrow() { NegotiateAuthenticationClientOptions clientOptions = new NegotiateAuthenticationClientOptions { Package = "NTLM", Credential = CredentialCache.DefaultNetworkCredentials, TargetName = "HTTP/foo" }; @@ -169,7 +166,7 @@ public static IEnumerable TestCredentials() yield return new object[] { new NetworkCredential("rightusername", "rightpassword") }; yield return new object[] { new NetworkCredential("rightusername", "rightpassword", "rightdomain") }; yield return new object[] { new NetworkCredential("rightusername@rightdomain.com", "rightpassword") }; - } + } [ConditionalTheory(nameof(IsNtlmAvailable))] [MemberData(nameof(TestCredentials))]