Accept all server certificates with HttpClient in Xamarin.Forms (including UWP)

Hello,

my app connects to a server that typically has a self signed certificate. I know that this is not perfect and I will show a warning to the user, but at least for now I need to able to accept all server certificates in my Xamarin.Forms project.

I use System.Net.Http.HttpClient and I have not found a universal solution.

ServerCertificateCustomValidationCallback and ServicePointManager.ServerCertificateValidationCallback are apparently not available for UWP.

How could I solve this issue to use Xamarin.Forms with an HttpClient that accepts all certificates?

Best Answers

  • kingmatherskingmathers ✭✭
    Accepted Answer

    In case anybody is having a similar problem: I solved this using DependecyService which implemented the Windows.Web.Http.Httpclient for UWP and the System.Net.Http.HttpClient version for Android/iOS. With this I was able to accept server certificates.

  • kingmatherskingmathers ✭✭
    Accepted Answer

    Hello,

    I will gladly share my code. I hope you are familiar with Dependency Service, otherwise this might be complicated.

    In my Xamarin.Forms app, I use this code on all platforms:

    public interface IServerCommunication
    {
        Task<string> GetFromServerAsync(string URL);
    }   
    
    //later on, when I download the data: (URL is a provided string)
    
    string result = await DependencyService.Get<IServerCommunication>().GetFromServerAsync(URL);
    

    I implement the interface for UWP and Android different. This is for UWP:

    public async Task<string> GetFromServerAsync(string URL)
    {
        HttpClient client = await PreparedClientAsync();
    
        HttpResponseMessage response;
    
        try
        {
            response = await client.GetAsync(new Uri(URL));
    
            IBuffer buffer = await response.Content.ReadAsBufferAsync();
            DataReader reader = DataReader.FromBuffer(buffer);
            byte[] fileContent = new byte[reader.UnconsumedBufferLength];
            reader.ReadBytes(fileContent);
            string result = Encoding.UTF8.GetString(fileContent, 0, fileContent.Length);
    
            return result;
        }
        catch (Exception ex)
        {
            return "error";
        }
    }
    
    private async Task<HttpClient> PreparedClientAsync()
    {
        var filter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
    
        filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
        filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
        filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
    
        HttpClient client = new HttpClient(filter);
    
        //I also handle other stuff here (client certificate, authentification), but the lines above should allow the Httpclient to accept all certificates
    
        return client;
    }
    

    This is for Android (should also work on iOS, but I have not tried it out):

    public async Task<string> GetFromServerAsync(string URL)
    {
        HttpClient client = PreparedClient();
    
        HttpResponseMessage response = new HttpResponseMessage();
    
        try
        {
            response = await client.GetAsync(URL);
            string result = await response.Content.ReadAsStringAsync();
            return result;
        }
        catch (Exception ex)
        {
            return "error";
        }
    }
    
    private HttpClient PreparedClient()
    {
        HttpClientHandler handler = new HttpClientHandler();
    
        //not sure about this one, but I think it should work to allow all certificates:
        handler.ServerCertificateCustomValidationCallback += (sender, cert, chaun, ssPolicyError) =>
        {
            return true;
        };
    
    
        HttpClient client = new HttpClient(handler);
    
        return client;
    }
    

Answers

  • AlmaJensen.9398AlmaJensen.9398 USMember ✭✭✭

    did you try calling the service using http instead of https?

    I haven't tried this myself but maybe it'll help.

    https://forums.xamarin.com/discussion/124695/exception-while-trying-to-connect-a-server-w-o-a-certificate

  • kingmatherskingmathers Member ✭✭

    No, it requires https.

    The link you provided only covers a solution using ServicePointManager.ServerCertificateValidationCallback which is (as far as I know) not available for UWP.

  • kingmatherskingmathers Member ✭✭
    Accepted Answer

    In case anybody is having a similar problem: I solved this using DependecyService which implemented the Windows.Web.Http.Httpclient for UWP and the System.Net.Http.HttpClient version for Android/iOS. With this I was able to accept server certificates.

  • OlivetreeOlivetree Member ✭✭

    @kingmathers could you please share your code with us? I am having this issue and I am having a hard time to implement the Dependency Service you were talking about.

    Thanks.

  • kingmatherskingmathers Member ✭✭
    Accepted Answer

    Hello,

    I will gladly share my code. I hope you are familiar with Dependency Service, otherwise this might be complicated.

    In my Xamarin.Forms app, I use this code on all platforms:

    public interface IServerCommunication
    {
        Task<string> GetFromServerAsync(string URL);
    }   
    
    //later on, when I download the data: (URL is a provided string)
    
    string result = await DependencyService.Get<IServerCommunication>().GetFromServerAsync(URL);
    

    I implement the interface for UWP and Android different. This is for UWP:

    public async Task<string> GetFromServerAsync(string URL)
    {
        HttpClient client = await PreparedClientAsync();
    
        HttpResponseMessage response;
    
        try
        {
            response = await client.GetAsync(new Uri(URL));
    
            IBuffer buffer = await response.Content.ReadAsBufferAsync();
            DataReader reader = DataReader.FromBuffer(buffer);
            byte[] fileContent = new byte[reader.UnconsumedBufferLength];
            reader.ReadBytes(fileContent);
            string result = Encoding.UTF8.GetString(fileContent, 0, fileContent.Length);
    
            return result;
        }
        catch (Exception ex)
        {
            return "error";
        }
    }
    
    private async Task<HttpClient> PreparedClientAsync()
    {
        var filter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
    
        filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
        filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
        filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
    
        HttpClient client = new HttpClient(filter);
    
        //I also handle other stuff here (client certificate, authentification), but the lines above should allow the Httpclient to accept all certificates
    
        return client;
    }
    

    This is for Android (should also work on iOS, but I have not tried it out):

    public async Task<string> GetFromServerAsync(string URL)
    {
        HttpClient client = PreparedClient();
    
        HttpResponseMessage response = new HttpResponseMessage();
    
        try
        {
            response = await client.GetAsync(URL);
            string result = await response.Content.ReadAsStringAsync();
            return result;
        }
        catch (Exception ex)
        {
            return "error";
        }
    }
    
    private HttpClient PreparedClient()
    {
        HttpClientHandler handler = new HttpClientHandler();
    
        //not sure about this one, but I think it should work to allow all certificates:
        handler.ServerCertificateCustomValidationCallback += (sender, cert, chaun, ssPolicyError) =>
        {
            return true;
        };
    
    
        HttpClient client = new HttpClient(handler);
    
        return client;
    }
    
Sign In or Register to comment.