我需要创建一个WCF客户端来调用我无法控制的服务,并且我们只获得了一个wsdl(带有模式)。 Web服务使用X.509证书和WS-Security规范版本1.0
Web服务提供者已共享soap消息的原始xml以突出显示ws-security标头。使用soapUI,我能够创建完全相同的wsse-Security标头,如下所示:
<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>
在soapUI中,在&#34; WS-Security配置&#34;我添加了Keystores(带有我的私有证书的jks)和Truststores(带有CA root公钥的jks)。最后,我添加了#34;传出WS-Security配置&#34;使用以下设置。
使用此WS-Security设置,soap消息会添加wsse:Security
,如上所示。
现在,我们正在使用WCF在.NET上构建WS客户端,并需要有关Binding和Security设置的帮助。可以使用哪些绑定和配置设置来获得上面所示或显示的相同WS-Security标头?
在WSDL中,我使用WSCF.blue创建了一个客户端代理。虽然,我也可以使用svcutil.exe或使用VS的添加服务引用。
我尝试在代码中创建customBinding,如下所示,但在检查此消息时,wsse
标题与我想要的不同。
例如,它会在BinarySecurityToken
标题中添加Security
,这是不可取的。
或KeyIdentifier
为X509SubjectKeyIdentifier
而不是X509v3
,例如:
<o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier" ...</o:KeyIdentifier>
它还在Reference
下添加了多个SignedInfo
,即使它通过了架构验证,我也不确定其他Reference
正在做什么。
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;
}
此外,我将此行为用于x509证书
<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>
答案 0 :(得分:3)
如果要发送完全相同的消息,则应该使用SignedXml类在WCF之外生成签名。使用WCF,您将无法获得精确的规范化算法/ InclusiveNamespace。
已经说过,大多数时候产生类似的消息对服务器来说都很好。你有两种可能的方法。一个是create a customMessageEncoder,它将在它到达网络之前更改传出的WCF消息。所以你可以告诉WCF创建一个极简主义的消息(例如没有时间戳),并在编码器中自己添加时间戳(如果wcf会创建它,那么它也会签名)并且还删除/更改x.509令牌引用。在执行do(body,signedInfo)(包括空格)时应该注意不要更改任何已签名的xml节点(因此如果加载到XmlDocument则使用preserveWhitepsaces)。
另一种方法是尝试配置WCF以发送相同的消息:
要排除额外的令牌引用,请创建x.509参数like this:
X509SecurityTokenParameters x509Params = new X509SecurityTokenParameters();
x509Params.X509ReferenceStyle =
X509KeyIdentifierClauseType.SubjectKeyIdentifier;
x509Params.RequireDerivedKeys = false;
;
x509Params.InclusionMode = SecurityTokenInclusionMode.Never;
x509Params.ReferenceStyle = SecurityTokenReferenceStyle.Internal;
x509Params.X509ReferenceStyle = X509KeyIdentifierClauseType.Any;
((AsymmetricSecurityBindingElement) sec).InitiatorTokenParameters = x509Params;
时间戳将由wcf签名,但服务器可能不在乎,或者不需要时间戳,因此请尝试requireTimestamp=true/false
并查看哪些有效。您可以使用MessagePartSpecification以编程方式停用signing for timestamps
。
这两种方法中的重要一点是要了解服务器可能比您想象的更灵活,并从错误消息中了解什么是真正的显示停止。