I need to consume a Java webservice with .NET. Requests must be signed, and the certificate needs to be included in the request.
When using the 'GetClient' method below, the request is generatec correct except for one field. In the SecurityTokenReference element, a 'KeyIdentifier' is added. This SecurityTokenReference field should contain a 'Reference' field to the third refence in the 'SignedInfo' element:
</o:Security>
</s:Header>
<o:BinarySecurityToken>...</o:BinarySecurityToken>
<Signature>
<SignedInfo>
<CanonicalizationMethod></CanonicalizationMethod>
<SignatureMethod></SignatureMethod>
<Reference URI="#_1">...</Reference>
<Reference URI="#uuid-001">...</Reference>
<Reference URI="#uuid-002">...</Reference>
</SignedInfo>
<SignatureValue>...</SignatureValue>
<KeyInfo>
<o:SecurityTokenReference>
<o:KeyIdentifier >...</o:KeyIdentifier>
</o:SecurityTokenReference>
</KeyInfo>
</Signature>
</o:Security>
</s:Header>
So
<o:SecurityTokenReference>
<o:KeyIdentifier >...</o:KeyIdentifier>
</o:SecurityTokenReference>
Should be
<o:SecurityTokenReference>
<o:Reference ValueType="..." URI="uuid-002" />
</o:SecurityTokenReference>
However i cannot get this working.
When using
InitiatorTokenParameters InclusionMode = SecurityTokenInclusionMode.Once
the correct 'Reference' tag is added, but then a double 'BinarySecurityToken' tag is generated, causing the webservice to be rejected. Is there any solution for this?
public wsClient GetClient()
{
CustomBinding b = new CustomBinding();
HttpsTransportBindingElement transport = new HttpsTransportBindingElement();
AsymmetricSecurityBindingElement asec = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement
(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
asec.SetKeyDerivation(false);
asec.AllowInsecureTransport = true;
asec.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256;
asec.IncludeTimestamp = true;
asec.ProtectTokens = true;
asec.SecurityHeaderLayout = SecurityHeaderLayout.Lax;
asec.InitiatorTokenParameters = new X509SecurityTokenParameters
{
InclusionMode = SecurityTokenInclusionMode.Never, //.Once, ----> Once creates correct SecurityTokenReference, but double BinarySecurityToken
ReferenceStyle = SecurityTokenReferenceStyle.Internal
};
asec.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters());
TextMessageEncodingBindingElement textMessageEncoding = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
b.Elements.Add(asec);
b.Elements.Add(textMessageEncoding);
b.Elements.Add(transport);
string url = "https://service";
var c = new wsClient(b, new EndpointAddress(new Uri(url),
new DnsEndpointIdentity(kgParams.DnsEndpointIdentity), new AddressHeaderCollection()));
X509Certificate cert = GetCertificate();
c.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(cert);
c.ClientCredentials.ServiceCertificate.DefaultCertificate = c.ClientCredentials.ClientCertificate.Certificate;
c.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.Sign;
return c;
}
After struggling for days with this issue, and not a single remark or answer on SO despite a bounty of 250 points, I can only come to the conclusion that this is an incompatibility between Java and .NET WCF.
In the end I simply abondoned WCF in frustration, and recreated the whole ***** request from scratch. This means:
The server accepted the request without any complaint.