I need to create a WCF client to call a service that I have no control over and we have been given a wsdl only (with schemas). The web service uses the X.509 certificate with the WS-Security specification version 1.0
The web service provider has shared raw xml of the soap message to highlight the ws-security header. Using the soapUI, I have been able to create the exact same wsse-Security header as shown below:
<soapenv:Envelope xmlns:oas="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:oas1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ds:Signature Id="SIG-32" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#id-31">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<InclusiveNamespaces PrefixList="oas oas1 urn urn1 urn2 urn3 xd" xmlns="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>ucSFZEOTHpe/IOlPVWtU+1xT4sM=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
d4CKqie==
</ds:SignatureValue>
<ds:KeyInfo Id="KI-9A8D1F611E86CFB79E144316684667546">
<wsse:SecurityTokenReference oas:Id="STR-9A8D1F611E86CFB79E144316684667547">
<wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">5lAB5TaqeFwo23mRVm31LngBT1dQMf94mxeVkyKog==
</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
<oas:Timestamp oas:Id="TS-30">
<oas:Created>2015-09-25T07:40:46.670Z</oas:Created>
<oas:Expires>2015-09-26T11:27:26.670Z</oas:Expires>
</oas:Timestamp>
</wsse:Security>
</soapenv:Header>
<soapenv:Body oas:Id="id-31">
...
</soapenv:Body>
</soapenv:Envelope>
In soapUI, under the "WS-Security Configurations" I added the Keystores (jks with my private cert) and Truststores (jks with CA root public key). Finally I added "Outgoing WS-Security Configurations" with the following setting.
With this WS-Security setting, the soap message adds the wsse:Security
as shown above.
Now, we are building the WS client on the .NET with WCF, and need help with the Binding and Security settings. What binding and configuration settings can be used to have the same WS-Security header as required or shown above?
From the WSDL, I created a client-side proxy using WSCF.blue. Although, I could have also used svcutil.exe or using Add Service Reference from VS.
I have tried creating the customBinding in code as following, but when inspecting this message the wsse
header is not the same as what I want.
For example, it adds a BinarySecurityToken
in the Security
header which is not desired.
Or the KeyIdentifier
is X509SubjectKeyIdentifier
instead of X509v3
for example:
<o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier" ...</o:KeyIdentifier>
It also adds additional multiple Reference
under the SignedInfo
, and even though it passes schema validation, I am not sure what the additional Reference
is doing.
internal static Binding GetCustomBinding()
{
CustomBinding myBinding = new CustomBinding();
AsymmetricSecurityBindingElement asBindingElement = new AsymmetricSecurityBindingElement();
//Have tried these also
//asBindingElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
//asBindingElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
//WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10
asBindingElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
asBindingElement.InitiatorTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.Never };
asBindingElement.RecipientTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters
{
//X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier,
InclusionMode = SecurityTokenInclusionMode.Never
};
asBindingElement.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
//asBindingElement.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
asBindingElement.SecurityHeaderLayout = SecurityHeaderLayout.LaxTimestampLast;
asBindingElement.EnableUnsecuredResponse = true;
asBindingElement.IncludeTimestamp = true;
asBindingElement.SetKeyDerivation(false);
asBindingElement.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128Rsa15;
asBindingElement.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters());
myBinding.Elements.Add(asBindingElement);
myBinding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
//myBinding.Elements.Add(new MtomMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
HttpsTransportBindingElement httpsBindingElement = new HttpsTransportBindingElement();
httpsBindingElement.RequireClientCertificate = true;
myBinding.Elements.Add(httpsBindingElement);
return myBinding;
}
Additionally, I am using this behaviour for the x509 cert
<behaviors>
<endpointBehaviors>
<behavior name="MyBehavior">
<clientCredentials>
<clientCertificate findValue="xxx"
storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" />
<serviceCertificate>
<defaultCertificate findValue="xxx"
storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" />
<authentication certificateValidationMode="None" revocationMode="NoCheck"
trustedStoreLocation="LocalMachine" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
See Question&Answers more detail:
os