0

Having a hard time converting a successful Postman request to a successful request in C#. Showing my code using HttpClient, but have also tried with PostSharp and HttpRequest. I am using a local pfx certificate file which has a password.

In Postman:

  • Added the PFX cert to Client Certificates
  • Authorization tab has username and password (Basic Auth)
  • Authorization header automatically generates based on above ("Basic <encoded username/password>")
  • Body is "{}"

Sends successfully (200).

Using HttpClient:

var host = @"https://thehost/service/verb?param1=blah&param2=1111111";
const string certName = @"C:\Key.pfx";
const string userName = "userName";
const string certPassword = "password1";
const string authPassword = "password2";

var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;

// tried many combinations here
handler.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 |
                       SslProtocols.Tls12 | SslProtocols.Tls13;

var cert = new X509Certificate2(certName, certPassword);
handler.ClientCertificates.Add(cert);
//not sure if this is needed
handler.ServerCertificateCustomValidationCallback += (message, certificate2, arg3, arg4) => true;
            
var client = new HttpClient(handler);
//not sure if these are needed
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.ConnectionClose = true;
// added this to both the request and the client. 
// Also tried "*/*" for both
client.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/json"));
            
var request = new HttpRequestMessage();
request.RequestUri = new Uri(host);
request.Headers.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/json"));
request.Content = new StringContent("{}", Encoding.UTF8, 
                                     "application/json");
request.Method = HttpMethod.Post;

//basic auth header
var authenticationString = $"{userName}:{authPassword}";
var base64EncodedAuthenticationString = Convert.ToBase64String(Encoding.UTF8.GetBytes(authenticationString));
var authHeader = new AuthenticationHeaderValue("Basic", 
                     base64EncodedAuthenticationString);
request.Headers.Authorization = authHeader;

try
{
   var httpResponseMessage = client.SendAsync(request).ConfigureAwait(false).GetAwaiter().GetResult();
}catch (Exception e){
   Console.WriteLine(e);
   throw;
}

This returns Unauthorized (401). The response text contains "Invalid user name or password."

Any thoughts on what might not be matching up between the two requests?

surfmuggle
  • 5,527
  • 7
  • 48
  • 77
Phil Sandler
  • 27,544
  • 21
  • 86
  • 147
  • 1
    Are you hitting a redirect with your request? By design, those aren't sent following a redirect request from the server – ESG Oct 11 '21 at 22:34
  • You could try to intercept your request (and the postman request) with a sniffer (eG wireshark or fiddler) to see if you're actually transmitting the same values. AFAIK setting the SslProtocols is not needed, just leave that line out. Furthermore the ServerCertificateCustomValidationCallback should result (for the server) into an expected hash. That being said; you mention the password should be encoded ("Basic "), but not the username although you encode both..? – riffnl Oct 11 '21 at 22:36
  • And indeed what @ESG states, redirects will strip all header values – riffnl Oct 11 '21 at 22:37
  • 1
    @ESG I considered redirects--I have turned off "Automatically follow redirects" in Postman and still get a success response (200). – Phil Sandler Oct 12 '21 at 11:22
  • @riffnl Username/password should both be encoded--I will edit the question. Not sure what you mean about ServerCertificateCustomValidationCallback--could you elaborate? I'll work towards getting the two requests captured in Fiddler. – Phil Sandler Oct 12 '21 at 11:32
  • @PhilSandler the callback (you deemed "not sure if it's needed") does actually supply an actual callback with a hash - so the callback does respond with a key the requesting party demands to see.. also see: https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler.servercertificatecustomvalidationcallback?view=net-5.0 , https://stackoverflow.com/questions/20914305/best-practices-for-using-servercertificatevalidationcallback – riffnl Oct 12 '21 at 23:39

2 Answers2

4

Have you tried using the Postman code snippets to auto-generate the code? It uses the RESTSharp REST API client library for C#.

Click on the </> icon and choose "C# - RestSharp" and it should give you code.

enter image description here

https://learning.postman.com/docs/sending-requests/generate-code-snippets/

w4dd325
  • 527
  • 5
  • 21
1

It is available in newer postman version(released in 10.10.6) https://github.com/postmanlabs/postman-code-generators/pull/453

Sanju
  • 11
  • 3