Search code examples
c#wcfiisssl

The HTTP request was forbidden with client authentication scheme 'Anonymous'. The remote server returned an error: (403) Forbidden


I am trying to create a secure webservice.

Here is the contract and service implementation

[ServiceContract()]
public interface ICalculatorService
{
    [OperationContract()]
    int Add(int x, int y);
}

[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class CalculatorService : ICalculatorService
{
    public int Add(int x, int y)
    {
        return x + y;
    }
}

Here i have the service code

var b = new WSHttpBinding(SecurityMode.Transport);
b.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
b.Security.Message.ClientCredentialType = MessageCredentialType.None;

Type contractType = typeof(ICalculatorService);
Type implementedContract = typeof(CalculatorService);
Uri baseAddress = new Uri("https://localhost:8006/CalculatorService");
ServiceHost sh = new ServiceHost(implementedContract);

sh.AddServiceEndpoint(contractType, b, baseAddress);

//ServiceMetadataBehavior sm = new ServiceMetadataBehavior();
//sm.HttpsGetEnabled = true;
//sm.HttpsGetUrl = new Uri("https://localhost:8006/CalculatorServiceMex");
//sh.Description.Behaviors.Add(sm);

sh.Credentials.Peer.PeerAuthentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.PeerTrust;
        sh.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindBySubjectName, "localhost");

sh.Open();
Console.WriteLine("Service is Listening");
Console.ReadLine();
sh.Close();

Here is the client code

var b = new WSHttpBinding(SecurityMode.Transport);
b.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
b.Security.Message.ClientCredentialType = MessageCredentialType.None;

var factory = new ChannelFactory<ICalculatorService>(b);
factory.Credentials.Peer.PeerAuthentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.PeerTrust;
        factory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindBySubjectName, "localhost");

var client = factory.CreateChannel(new EndpointAddress(new Uri("https://localhost:8006/CalculatorService")));

ServicePointManager.ServerCertificateValidationCallback =
   ((sender, certificate, chain, sslPolicyErrors) =>
            {
                return true;
            });

ICommunicationObject comObject = client as ICommunicationObject;
int result = -1;
try
{
  comObject.Open();
  result = client.Add(10, 2);
}
catch (Exception ex)
{

}
Console.WriteLine(string.Format("Service say 10 + 2 = {0}", -1));
Console.ReadLine();

The service runs fine and when the ServicePointManager.ServerCertificateValidationCallback check is made there are no policy errors, with the correct certificate chain built.

enter image description here

I have my CA in the trusted root and the server/client cert in the TrustedPeople store. Also if I navigate to the site from a browser I see a page returned. No errorsenter image description here

I have updated IIS to what I think are the required, bound the certificate in in IIS enter image description here

and via command line below. enter image description here

I've set the SSL settings to accept certificates enter image description here

and enabled anonymous authentication. enter image description here

Does anyone know what steps I've not done correctly or see anything amiss? I keep getting the same error "The HTTP request was forbidden with client authentication scheme 'Anonymous'."


Solution

  • There is a registry entry located at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL. Setting that value to 0 fixes the issue. Some other potential solutions are outlined in this here. I had an existing answer which cited Method 3 and had a number of upvotes from the page referenced but was removed for unknown reasons by a moderator. Reposting in case it helps someone else in the future.