I'm working in a big project that makes extensive use of WCF for different kinds of communication. As a part of a new requirement, we need to communicate with a SOAP Web Service developed by a third party. Their service is developed with Java and has two security requirements:
it needs BASIC authentication over transport and
the message has to be signed (not encrypted) with a X509 certificate using the WS-Security (OASIS) standard for non-repudiation.
The problem I have is that the bindings provided by WCF allow using either transport or message security, but not both at the same time. As a result I can either sign the SOAP message or send BASIC authentication credentials, but so far I haven't been able to do both as I require.
I have been trying to find a solution for days, and so far I have concluded that probably my best shot is to make a custom binding programmatically. Using several sources, this is what I have right now:
var b = new CustomBinding();
var sec = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10);
UserNameSecurityTokenParameters tokenParamenters = new UserNameSecurityTokenParameters();
tokenParamenters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
tokenParamenters.RequireDerivedKeys = false;
b.Elements.Add(sec);
b.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
b.Elements.Add(new HttpsTransportBindingElement());
WSClient svc = new WSClient(b, new EndpointAddress(new Uri("https://serviceurl.com/SoapWS"), new DnsEndpointIdentity("CertificateIdentity"), new AddressHeaderCollection()));
svc.ClientCredentials.UserName.UserName = "username";
svc.ClientCredentials.UserName.Password = "password";
svc.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2("Certificate.p12", "password");
svc.ClientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2("Certificate.p12", "password");
svc.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
string resp = svc.DoSomething();
While this seems to be signing the message with the certificate (haven't been able to fully check), the basic authentication part is not happening. The response from the server is:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Basic realm="realm"'.
Any insights on how I could get this binding to authenticate over transport with BASIC authentication would be very helpful. Thanks in advance.
PS: please note that I have no control over the web service I am trying to communicate with.