问题
I need to create a WCF client who calls a bea webservice.
I keep getting this response from the webservice:
Could not validate signature using any of the supported token types
So I turn my attention to the signature part of the client<->service communication:
Part of the wsdl from the webservice:
<s0:Policy s1:Id="Sign.xml">
<wssp:Integrity xmlns:wls="http://www.bea.com/wls90/security/policy/wsee#part"
xmlns:wssp="http://www.bea.com/wls90/security/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wssp:SignatureAlgorithm URI="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<wssp:CanonicalizationAlgorithm URI="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<wssp:Target>
<wssp:DigestAlgorithm URI="http://www.w3.org/2000/09/xmldsig#sha1"/>
<wssp:MessageParts Dialect="http://www.bea.com/wls90/security/policy/wsee#part">
wls:SystemHeaders()
</wssp:MessageParts>
</wssp:Target>
<wssp:Target>
<wssp:DigestAlgorithm URI="http://www.w3.org/2000/09/xmldsig#sha1"/>
<wssp:MessageParts Dialect="http://www.bea.com/wls90/security/policy/wsee#part">
wls:SecurityHeader(wsu:Timestamp)
</wssp:MessageParts>
</wssp:Target>
<wssp:Target>
<wssp:DigestAlgorithm URI="http://www.w3.org/2000/09/xmldsig#sha1"/>
<wssp:MessageParts Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">
wsp:Body()
</wssp:MessageParts>
</wssp:Target>
<wssp:SupportedTokens>
<wssp:SecurityToken
IncludeInMessage="true"
TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">
<wssp:TokenIssuer>REMOVED</wssp:TokenIssuer>
</wssp:SecurityToken>
</wssp:SupportedTokens>
</wssp:Integrity>
<wssp:MessageAge Age="60" xmlns:wssp="http://www.bea.com/wls90/security/policy"/>
From the wsdl i understand that I must sign:
- SystemHeaders (my real problem)
- Timestamp (did that)
- Body (did that, and also encrypted it)
I have working code (using microsoft.web.services3) who produce this soap:
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<ds:CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="#Timestamp-fc23bf88-381b-4f2b-b992-ff07b41b5c38"> <!--This is the timestamp-->
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>Removed</DigestValue>
</Reference>
<Reference URI="#Id-4b4f1377-eac0-4db0-b334-384d7b14e286"> <!--This is the encrypted body-->
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>Removed</DigestValue>
</Reference>
<Reference URI="#SecurityToken-dcb8a392-5907-4432-80c6-cbe8f29a6117"> <!--This is the SecurityTokenReference:Reference-->
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>Removed</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>Removed</SignatureValue>
<KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference
URI="#SecurityToken-dcb8a392-5907-4432-80c6-cbe8f29a6117"
ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" />
</wsse:SecurityTokenReference>
</KeyInfo>
</Signature>
</wsse:Security>
</soap:Header>
<soap:Body wsu:Id="Id-4b4f1377-eac0-4db0-b334-384d7b14e286">
<xenc:EncryptedData
Id="Enc-8b5b4ef4-1c12-409b-8159-dec2889a8fa8"
Type="http://www.w3.org/2001/04/xmlenc#Content"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
<xenc:CipherData>
<xenc:CipherValue>Removed<xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</soap:Body>
I have promised to make this work using WCF, so microsoft.web.services3 is not an option. Sorry.
I have created the proxy using svcutil. No sweat. Only change I have made to the proxy by hand is that I have appended
, ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign
to the System.ServiceModel.ServiceContractAttribute
My current code produces this sign part:
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="#_1"> <!--This is the body-->
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>Removed</DigestValue>
</Reference>
<Reference URI="#uuid-e7f22d2b-5a91-421a-aced-df7ab8a92f8d-1"> <!--This is the timestamp-->
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>Removed</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>Removed</SignatureValue>
<KeyInfo>
<o:SecurityTokenReference>
<o:Reference
ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"
URI="#uuid-3b0e28b3-d47f-4eb2-ab0a-77f94dd76af0-2"/>
</o:SecurityTokenReference>
</KeyInfo>
</Signature>
</o:Security>
</s:Header>
<s:Body u:Id="_1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<e:EncryptedData
Id="_2"
Type="http://www.w3.org/2001/04/xmlenc#Content"
xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
<e:CipherData><e:CipherValue>Removed</e:CipherValue></e:CipherData>
</e:EncryptedData>
</s:Body>
</s:Envelope>
from my app.config:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="testBinding">
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap11" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192"
maxArrayLength="16384" maxBytesPerRead="4096"
maxNameTableCharCount="16384"/>
</textMessageEncoding>
<httpTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" allowCookies="false"
authenticationScheme="Anonymous" bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard" keepAliveEnabled="true"
maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered"
unsafeConnectionNtlmAuthentication="false" useDefaultWebProxy="true"/>
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://url.com/testservice/testservicePort" binding="customBinding"
bindingConfiguration="testBinding"
contract="testservicePortType"
name="testservicePort"/>
</client>
</system.serviceModel>
I configure the CustomBinding in code like this:
private static CustomBinding CreateCustomBinding()
{
var customBinding = new CustomBinding();
SecurityBindingElement securityBindingElement = SecurityBindingElement.CreateMutualCertificateBindingElement(
MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
AsymmetricSecurityBindingElement asymmetricSecurityBindingElement =
(AsymmetricSecurityBindingElement)securityBindingElement;
asymmetricSecurityBindingElement.SetKeyDerivation(false);
asymmetricSecurityBindingElement.EnableUnsecuredResponse = true;
asymmetricSecurityBindingElement.AllowInsecureTransport = true;
asymmetricSecurityBindingElement.AllowSerializedSigningTokenOnReply = true;
asymmetricSecurityBindingElement.DefaultAlgorithmSuite = SecurityAlgorithmSuite.TripleDesRsa15;
asymmetricSecurityBindingElement.IncludeTimestamp = true;
asymmetricSecurityBindingElement.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;
asymmetricSecurityBindingElement.RequireSignatureConfirmation = false;
asymmetricSecurityBindingElement.SecurityHeaderLayout = SecurityHeaderLayout.LaxTimestampFirst;
customBinding.Elements.Clear();
customBinding.Elements.Add(asymmetricSecurityBindingElement);
customBinding.Elements.Add(new TextMessageEncodingBindingElement()
{
MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap11,
AddressingVersion.None),
WriteEncoding = new System.Text.UTF8Encoding()
});
HttpTransportBindingElement httpbinding = new HttpTransportBindingElement();
httpbinding.AuthenticationScheme = AuthenticationSchemes.Anonymous;
httpbinding.MaxReceivedMessageSize = 1024 * 1024;
customBinding.Elements.Add(httpbinding);
return customBinding;
}
I have tried to understand what happens in the microsoft.web.services3 code who works (I havent written it), and it seems like the author completely rewrites the securityheader. This doesnt seem like the best solution (but maybe the only?)
Could anyone help me?
回答1:
Finally figured it out :-)
Used this post:
How to make WCF Client conform to specific WS-Security - sign UsernameToken and SecurityTokenReference
Have read it several times before i wrote the question above (hence the titles are so similar), and could really not see why it should work. But it does!
My custom binding now looks like this:
System.ServiceModel.Channels.AsymmetricSecurityBindingElement
asymmetricSecurityBindingElement = new AsymmetricSecurityBindingElement();
asymmetricSecurityBindingElement.MessageSecurityVersion =
MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
asymmetricSecurityBindingElement.InitiatorTokenParameters = new
System.ServiceModel.Security.Tokens.X509SecurityTokenParameters
{ InclusionMode = SecurityTokenInclusionMode.Never };
asymmetricSecurityBindingElement.RecipientTokenParameters = new
System.ServiceModel.Security.Tokens.X509SecurityTokenParameters
{ InclusionMode = SecurityTokenInclusionMode.Never };
asymmetricSecurityBindingElement.MessageProtectionOrder =
System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
asymmetricSecurityBindingElement.SecurityHeaderLayout = SecurityHeaderLayout.LaxTimestampFirst;
asymmetricSecurityBindingElement.EnableUnsecuredResponse = true;
asymmetricSecurityBindingElement.IncludeTimestamp = true;
asymmetricSecurityBindingElement.SetKeyDerivation(false);
asymmetricSecurityBindingElement.DefaultAlgorithmSuite =
System.ServiceModel.Security.SecurityAlgorithmSuite.TripleDesRsa15;
asymmetricSecurityBindingElement.EndpointSupportingTokenParameters.Signed.Add(
new X509SecurityTokenParameters());
customBinding.Elements.Clear();
customBinding.Elements.Add(asymmetricSecurityBindingElement);
来源:https://stackoverflow.com/questions/13453921/how-to-make-wcf-client-sign-securitytokenreferencereference