Skip to content

Android NTLM: Empty Credentials now throws PlatformNotSupportedException #91131

Closed

Description

Description

If an empty network credential is used a recent change is now causing the exception System.PlatformNotSupportedException: 'NTLM authentication is not possible with default credentials on this platform.' to be thrown rather than treating the empty credential as null / not set.
This is a regression from .NET 7 behavior.

Reproduction Steps

On .NET Android, run the folllowing code:

string url = "https://url.to/my-iwa-secured-server";
var handler = new SocketsHttpHandler();
var cre = handler.Credentials;
handler.Credentials = CredentialCache.DefaultCredentials; // this is empty string username+password
//OR: handler.Credentials = new NetworkCredential();
HttpClient client = new HttpClient(handler);            
var result = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, url)); // Throws

Expected behavior

Returns 401 like .NET 7 would.

Actual behavior

[mono-rt] [ERROR] FATAL UNHANDLED EXCEPTION: System.PlatformNotSupportedException: NTLM authentication is not possible with default credentials on this platform.
[mono-rt]    at System.Net.NegotiateAuthenticationPal.ManagedNtlmNegotiateAuthenticationPal..ctor(NegotiateAuthenticationClientOptions clientOptions)
[mono-rt]    at System.Net.NegotiateAuthenticationPal.Create(NegotiateAuthenticationClientOptions clientOptions)
[mono-rt]    at System.Net.NegotiateAuthenticationPal.ManagedSpnegoNegotiateAuthenticationPal.CreateMechanismForPackage(String packageName)
[mono-rt]    at System.Net.NegotiateAuthenticationPal.ManagedSpnegoNegotiateAuthenticationPal.CreateSpNegoNegotiateMessage(ReadOnlySpan`1 incomingBlob, NegotiateAuthenticationStatusCode& statusCode)
[mono-rt]    at System.Net.NegotiateAuthenticationPal.ManagedSpnegoNegotiateAuthenticationPal.GetOutgoingBlob(ReadOnlySpan`1 incomingBlob, NegotiateAuthenticationStatusCode& statusCode)
[mono-rt]    at System.Net.Security.NegotiateAuthentication.GetOutgoingBlob(ReadOnlySpan`1 incomingBlob, NegotiateAuthenticationStatusCode& statusCode)
[mono-rt]    at System.Net.Security.NegotiateAuthentication.GetOutgoingBlob(String incomingBlob, NegotiateAuthenticationStatusCode& statusCode)
[mono-rt]    at System.Net.Http.AuthenticationHelper.SendWithNtAuthAsync(HttpRequestMessage request, Uri authUri, Boolean async, ICredentials credentials, Boolean isProxyAuth, HttpConnection connection, HttpConnectionPool connectionPool, CancellationToken cancellationToken)
[mono-rt]    at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
[mono-rt]    at System.Net.Http.AuthenticationHelper.SendWithAuthAsync(HttpRequestMessage request, Uri authUri, Boolean async, ICredentials credentials, Boolean preAuthenticate, Boolean isProxyAuth, Boolean doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
[mono-rt]    at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
[mono-rt]    at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
[mono-rt]    at IWATest.MainPage.OnCounterClicked(Object sender, EventArgs e) in E:\sources.tmp\IWATest\IWATest\MainPage.xaml.cs:line 25
[mono-rt]    at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state)
[mono-rt]    at Android.App.SyncContext.<>c__DisplayClass2_0.<Post>b__0() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.App/SyncContext.cs:line 36
[mono-rt]    at Java.Lang.Thread.RunnableImplementor.Run() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Java.Lang/Thread.cs:line 36
[mono-rt]    at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-34/mcw/Java.Lang.IRunnable.cs:line 84
[mono-rt]    at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V(_JniMarshal_PP_V callback, IntPtr jnienv, IntPtr klazz) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 22

Regression?

Yes

Known Workarounds

Check whether the credential is empty before setting, but has effect on already released libraries or cross-platform code.

Configuration

.NET 8 Preview 7 (Android)

Other information

/CC @wfurt @filipnavara as discussed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions