dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.56k stars 4.54k forks source link

[iOS] Different behavior of HttpClient depending on OS. Digest authentication #101787

Open Paul-N opened 2 months ago

Paul-N commented 2 months ago

Description

HttpClient with Digest auth is working fine in .net8 console app. On net8-ios requests are failing with Status 401. I attached repository with the code to reproduce (see below).

Reproduction Steps

Let's say we have a service that is working with httpbin.org site with Digest auth.

internal class Consts
{
    public const string Url = "https://httpbin.org/digest-auth/undefined/usr/pwd";

    public const string User = "usr";

    public const string Password = "pwd";
}

public interface IHttpBinService
{
    Task<string> GetData();
}

public class ClientBasedHttpBinService : IHttpBinService
{
    private readonly HttpClient _httpClient;

    public ClientBasedHttpBinService()
    {
        var handler = new HttpClientHandler()
        {
            Credentials = new NetworkCredential(Consts.User, Consts.Password),
        };
        _httpClient = new HttpClient(handler);

    }

    public async Task<string> GetData()
        => await _httpClient.GetStringAsync(Consts.Url);
}

This code will work fine in console apps but will fail in iOS/Android app with 401 status code

Expected behavior

Digest auth should work (or not work) the same way on every OS supported by modern net8. In this case I expect code 200 in console app and in mobile apps.

Actual behavior

Digest auth work in console app and doesn't work in mobile apps (iOS/Android)

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

See https://github.com/Paul-N/DigestAuthDemo repository. It consist of 3 projects. They all have a service interface IHttpBinService that is working with httpbin.org website. The projects are: net8 console app, net8-ios iOS app (no MAUI, just basic native UI to test), Xamarin iOS app with the same UI.

The service interface IHttpBinService has two implementations: one with HttpClient and another with NSUrlSession (native iOS way to make a HTTP requests). The console app is able to call only HttpClient based service. The two iOS app can call both implementations.

How to test:

  1. Run console app, see output, it is fine.
  2. Run DigestAuthDemo.Xamarin_iOS app, click [HttpClient] button, response is Ok. Click [Clear] button. Click [NsUrlSession] response is also Ok.
  3. Run DigestAuthDemo.Net8_iOS app, click [HttpClient] button, response is Error. Click [Clear] button. Click [NsUrlSession] response is Ok.

⚠️ Strange behavior: If you are running DigestAuthDemo.Net8_iOS and you hit [NsUrlSession] BEFORE [HttpClient] button then HttpClient will work fine.

dotnet-policy-service[bot] commented 2 months ago

Tagging subscribers to this area: @dotnet/ncl See info in area-owners.md if you want to be subscribed.

wfurt commented 2 months ago

I think it may be the platform handler. Can you try it with var handler = new SocketsHttpHandler() @Paul-N ? That should give you consistent behavior. Note that Digest depends on MD5 and that is not considered safe in modern times.

Paul-N commented 2 months ago

Can you try it with var handler = new SocketsHttpHandler() @Paul-N ?

Yes, this fixed the bug...

wfurt commented 2 months ago

well, not really but at least you have something to work with. I'll leave it open for iOS folks to look at it.

CarnaViire commented 2 months ago

@vitek-karas @kotlarmilos can you please triage this iOS issue? Thanks!

vitek-karas commented 2 months ago

@simonrozsival can you please take a look?

simonrozsival commented 2 months ago

As far as I can tell, Digest auth is not implemented in the iOS platform handler (unlike it is in the managed SocketsHttpHandler and in Android's native AndroidMessageHandler). This is certainly something that either needs to be documented as a known limitation, or it should be implemented in the native iOS handler.

wfurt commented 1 month ago

If easy we can perhaps share implementation. Digest is not considered secure as it depends on long deprecated md5. So you would not stress too much about it. Documentation would certainly be helpful to avoid pitfalls but I'm not sure where you would put it. At least workaround exists.