1

We are writing a client to a WCF service that uses both a CSR certificate and basic authentication.

Our C# client is generated via Visual Studio and we can programmatically set the certificate and the username/password. However, we have to manually send the Basic Auth header otherwise we receive the error:

'The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Basic realm="HttpBasicAuthentication"'.'

Our code is:

var myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;

var ea = new EndpointAddress("https://example.org/myservice");
var client = new MandateWebServiceClient(myBinding, ea);
client.ClientCredentials.UserName.UserName = "wally";
client.ClientCredentials.UserName.Password = "walliesWorld";
client.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2("C:\\some\\path\\to\\csr.pfx", "password");

using (var scope = new OperationContextScope(client.InnerChannel))
{
    var httpRequestProperty = new HttpRequestMessageProperty();
    httpRequestProperty.Headers[HttpRequestHeader.Authorization] =
        "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(client.ClientCredentials.UserName.UserName + ":" + client.ClientCredentials.UserName.Password));
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;

    client.create();
}

With the above code, we can successfully talk to the service. If we remove the lines in the using block, the authentication scheme changes to Anonymous, and we get the error above.

The above arrangement seems a little hackey. We have tried all the SecurityMode settings possible and SecurityMode.Transport with HttpClientCredentialType.Certificate is the only combination that allows the certificate to be accepted. Setting or not setting MessageCredentialType.UserName appears to have no effect on the system.

Is there any .Net Framework way of providing both the certificate and the basic authentication header rather than manually adding the header?

user626201
  • 1,623
  • 3
  • 19
  • 36

1 Answers1

1

How does the server use both Certificate authentication and Basic authentication? This seems superfluous. Because it is secure to authenticate the client with a certificate (issue the certificate and establish the relationship between the server and client), why do we need to authenticate the client with Basic Authentication? Thereby, are you sure that the client needs to provide a certificate? In my opinion, the server may have used Transport Security mode, and set up a Basic authentication, so the client may need not to provide a certificate.
Here is the server side configuration I thought.
Server.

Uri uri = new Uri("https://localhost:9900");
        WSHttpBinding binding = new WSHttpBinding();
        binding.Security.Mode = SecurityMode.Transport;
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

Client (invocation by adding service reference, the client proxy class/binding type is auto-generated via the service MEX endpoint, https://localhost:9900/mex)

ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
            client.ClientCredentials.UserName.UserName = "administrator";
            client.ClientCredentials.UserName.Password = "abcd1234!";

Based on this, I have a question, what is the auto-generated binding type on the client side when calling the service by adding service reference?
Look forward to your reply.

Abraham Qian
  • 7,117
  • 1
  • 8
  • 22
  • `why do we need to authenticate the client with Basic Authentication?` Because this is a third party service that I have no control over. `are you sure that the client needs to provide a certificate?` Yes, because if I don't provide the certificate there is the usual error that trust could not be established. Even on SoapUI, basic auth and the certificate need to be provided. `what is the auto-generated binding type on the client side when calling the service by adding service reference?` We were provided with the wsdl, so it was generated from a file, not web reference. – user626201 Jul 08 '19 at 08:37
  • the last reply doesn't make sense, the reference.cs and client configuration will be generated still. we can check the binding type, do we? Besides, provided that third-party authentication does include basic certification, there can be other ways, but it will not be easier. it still manually write the http header. – Abraham Qian Jul 08 '19 at 09:29
  • Add basic header to all outbound messages using the client IClientmessageinspector interface https://stackoverflow.com/questions/48512493/adding-http-header-in-an-existing-wcf-soap-service-is-not-working – Abraham Qian Jul 08 '19 at 09:30
  • `the reference.cs and client configuration will be generated still` Yes, ran out of characters :) `we can check the binding type` The binding type is the same as the `myBinding.Security.Transport.ClientCredentialType` setting in the code snippet (unless I'm misunderstanding you) `` – user626201 Jul 08 '19 at 09:38
  • It seems the actual scenario is what you described. I have no idea. Besides, one more question, how do you set up the certificate authentication on the client side, since similar errors occur when the client and the server don't install each other's certificate. – Abraham Qian Jul 09 '19 at 06:37
  • `how do you set up the certificate authentication on the client side` we setup the client certificate in the client credentials (`.pfx`) and with transport security, it uses that certificate. – user626201 Jul 09 '19 at 13:04
  • As far as I know , we should install the server certificate in the local RootCA,and install the client certificate in the server RootCA, so that establishes the trust relationship between the server and the client – Abraham Qian Jul 09 '19 at 13:20
  • https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-certificate-authentication – Abraham Qian Jul 09 '19 at 13:22
  • 1
    We manage a number of servers that the client runs on. Spinning up machines and ensuring the certificate is installed correctly is what we are wanting to avoid, if at all possible. Even if the certificate is installed, the transport mode still seems to need to be set as wcf needs to use the cert. In the above we are supplying the X509 cert via a file, not a keystore. – user626201 Jul 10 '19 at 19:19
  • Yes. Regardless of whether we have installed the certificate, we should provide a client certificate as client identity. It seems that you make a successful call given that the certificate is not installed. It is beyond the scope of what I have known, welcome to share the new progress of the issue with me. – Abraham Qian Jul 23 '19 at 01:50