Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flurl and untrusted certificates

Currently I worked on Flurl and I tried to contact an API in https (I am in my lab). So the certificate is not valid and Flurl can't continue to work :/

Here is my error message:

Unhandled Exception: System.AggregateException: One or more errors occurred. (Call failed. The SSL connection could not be established, see inner exception. POST https://IP/api/aaaLogin.json) ---> Flurl.Http.FlurlHttpException: Call failed. The SSL connection could not be established, see inner exception. POST https://IP/api/aaaLogin.json ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.

In Flurl documentation we can use using Flurl.Http.Configuration; and modify the DefaultHttpClientFactory However I do not understand the elements specified to say of jumped over the errors.

On the web I can see the same case: https://github.com/tmenier/Flurl/issues/365 Do you have an issue for this problem?

Thank you!

like image 685
Digitag Avatar asked Dec 19 '18 14:12

Digitag


3 Answers

The most typical way to do this is to create a custom factory:

public class UntrustedCertClientFactory : DefaultHttpClientFactory
{
    public override HttpMessageHandler CreateMessageHandler() {
        return new HttpClientHandler {
            ServerCertificateCustomValidationCallback = (_, _, _, _) => true
        };
    }
}

Then register it somewhere in your app startup:

FlurlHttp.ConfigureClient("https://theapi.com", cli =>
    cli.Settings.HttpClientFactory = new UntrustedCertClientFactory());

Flurl reuses the same HttpClient instance per host by default, so configuring this way means that every call to theapi.com will allow the use of the untrusted cert. The advantage of this over passing an HttpClient to a FlurlClient constructor is that it keeps this configuration "off to the side" and works when you use Flurl in the more typical/less verbose way:

await "https://theapi.com/endpoint".GetJsonAsync();
like image 125
Todd Menier Avatar answered Nov 17 '22 20:11

Todd Menier


Here is my setup for Flurl, which works with untrusted certificates:

HttpClientHandler httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, 
  errors) => true;
HttpClient httpClient = new HttpClient(httpClientHandler);
httpClient.BaseAddress = new Uri("https://myaddress.com");
var flurlClient = new FlurlClient(httpClient);

var apiInfo = await flurlClient.Request("apiInfo").GetJsonAsync<ApiInfoDto>();

I have created custom HttpClientHandler which accepts every certificate in ServerCertificateCustomValidationCallback. Of course, you can use other logic in this handler.

Update: With this setup, you cannot use Flurl extensions for URL (you cannot write "http://myadress.com/apiInfo".GetJsonAsync<ApiInfoDto>(). You have to create Flurl client as seen above and use Flurl client for your calls as demonstrated also in mine code. The usage is the same as Flurl extensions for URL.

like image 6
Karel Kral Avatar answered Nov 17 '22 20:11

Karel Kral


An inline solution to accept any certificate is:


var myString = await "https://some-server-with-an-invalid-cert.net"
    .AppendPathSegment("/some-file.txt")
    .WithClient(new FlurlClient(new HttpClient(new HttpClientHandler
              {
                  ServerCertificateCustomValidationCallback = (message, cert, chain,
                                                               errors) => true
              })))
    .GetStringAsync();

With WithClient() you can pass a client configured different than the default client. In some cases you would not want to change the default client, but apply properties, e.g. the certificate validation only to this specific case.

like image 4
lufist Avatar answered Nov 17 '22 22:11

lufist