Skip to content

Android NTLM: Empty Credentials now throws PlatformNotSupportedException #91131

Closed
@dotMorten

Description

@dotMorten

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions