我尝试使用WCF客户端连接到基于Java的Web服务
我提供的证书(自签名)在SOAPUI中完美运行。
这是我的设置:
但是,我在使用WCF客户端时遇到了问题。
我的 app.config
<bindings>
<customBinding>
<binding name="Example_TestBinding">
<security defaultAlgorithmSuite="TripleDesRsa15"
authenticationMode="MutualCertificate"
requireDerivedKeys="false"
includeTimestamp="false"
messageProtectionOrder="SignBeforeEncrypt"
messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10"
requireSignatureConfirmation="false">
<localClientSettings detectReplays="true"/>
<localServiceSettings detectReplays="true"/>
</security>
<textMessageEncoding messageVersion="Soap11"/>
<httpsTransport authenticationScheme="Basic" manualAddressing="false" maxReceivedMessageSize="524288000" transferMode="Buffered"/>
</binding>
</customBinding>
</bindings>
<client>
<endpoint
address="https://blabla.hana.ondemand.com/Example_Test"
binding="customBinding"
bindingConfiguration="Example_TestBinding"
contract="WebServiceTest.Example_Test"
name="Example_Test"
/>
</client>
使用Keystore Explorer我将来自JKS的两个证书导出为:
网络服务电话:
var client = new Example_TestClient();
client.ClientCredentials.UserName.UserName = "user";
client.ClientCredentials.UserName.Password = "pass";
X509Certificate2 certClient = new X509Certificate2(certClientPath, certClientPassword);
client.ClientCredentials.ClientCertificate.Certificate = certClient;
X509Certificate2 certService= new X509Certificate2(certServicePath);
client.ClientCredentials.ServiceCertificate.DefaultCertificate = certService;
var response = client.Example_Test(requestObj);
请求完全到达服务器但是看起来WCF并不理解响应,因为我得到了这个异常:
"The EncryptedKey clause was not wrapped with the required
encryption token 'System.IdentityModel.Tokens.X509SecurityToken'."
at System.ServiceModel.Security.WSSecurityJan2004.WrappedKeyTokenEntry.CreateWrappedKeyToken(String id, String encryptionMethod, String carriedKeyName, SecurityKeyIdentifier unwrappingTokenIdentifier, Byte[] wrappedKey, SecurityTokenResolver tokenResolver)\r\n ...
服务跟踪给出:
The security protocol cannot verify the incoming message
UPDATE1 :使用相同的证书进行签名和加密,简化了任务。同样的消息。
UPDATE2 :我编写了CustomTextMessageEncoder,我手动解密邮件正文并且可以正常工作。但是,在ReadMessage中返回它仍会引发错误。
public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
{
var msgContents = new byte[buffer.Count];
Array.Copy(buffer.Array, buffer.Offset, msgContents, 0, msgContents.Length);
bufferManager.ReturnBuffer(buffer.Array);
var message = Encoding.UTF8.GetString(msgContents);
//return ReadMessage(Decryptor.DecryptBody(message), int.MaxValue);
var stream = new MemoryStream(Encoding.UTF8.GetBytes(message));
return ReadMessage(stream, int.MaxValue);
}
public static MemoryStream DecryptBody(string xmlResponse)
{
X509Certificate2 cert = new X509Certificate2(clientCertPath, certPass);
SymmetricAlgorithm algorithm = new TripleDESCryptoServiceProvider();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.LoadXml(xmlResponse);
XmlElement encryptedKeyElement = xmlDoc.GetElementsByTagName("EncryptedKey", XmlEncryptionStrings.Namespace)[0] as XmlElement;
XmlElement keyCipherValueElement = encryptedKeyElement.GetElementsByTagName("CipherValue", XmlEncryptionStrings.Namespace)[0] as XmlElement;
XmlElement encryptedElement = xmlDoc.GetElementsByTagName("EncryptedData", XmlEncryptionStrings.Namespace)[0] as XmlElement;
var key = Convert.FromBase64String(keyCipherValueElement.InnerText);
EncryptedData edElement = new EncryptedData();
edElement.LoadXml(encryptedElement);
EncryptedXml exml = new EncryptedXml();
algorithm.Key = (cert.PrivateKey as RSACryptoServiceProvider).Decrypt(key, false);
byte[] rgbOutput = exml.DecryptData(edElement, algorithm);
exml.ReplaceData(encryptedElement, rgbOutput);
//var body = Encoding.UTF8.GetString(rgbOutput);
MemoryStream ms = new MemoryStream();
xmlDoc.Save(ms);
return ms;
}
答案 0 :(得分:7)
我在项目的最后冲刺中留下了这个问题,最后又回到了它 证书问题。我使用KeyStore Explorer生成了基于Java的Web服务提供的自签名证书。两个证书都缺少一个重要部分:
Subject Key Identifier
重新生成的WCF能够在不使用编码器的情况下对其进行解密。
我也必须:
我从代码中删除了所有配置(客户端用户名和密码除外)并放在app.config中。这是完整的配置:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="Example_TestBinding">
<security
defaultAlgorithmSuite="TripleDesRsa15"
authenticationMode="MutualCertificate"
requireDerivedKeys="false"
includeTimestamp="true"
messageProtectionOrder="SignBeforeEncrypt"
messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireSignatureConfirmation="false"
allowSerializedSigningTokenOnReply="true"
>
</security>
<textMessageEncoding messageVersion="Soap11"/>
<httpsTransport authenticationScheme="Basic"
manualAddressing="false"
maxReceivedMessageSize="524288000"
transferMode="Buffered"/>
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="https://klaatuveratanecto.com/cxf/Example_TestBinding"
behaviorConfiguration="endpointCredentialBehavior"
binding="customBinding"
bindingConfiguration="Example_TestBinding"
contract="WebServiceTest.Example_Test"
name="Example_Test">
<identity>
<dns value="test.service.klaatuveratanecto.com"/>
</identity>
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="endpointCredentialBehavior">
<clientCredentials>
<serviceCertificate>
<defaultCertificate findValue="test.service.klaatuveratanecto.com"
storeLocation="CurrentUser"
storeName="Root"
x509FindType="FindBySubjectName" />
</serviceCertificate>
<clientCertificate findValue="test.client.klaatuveratanecto.com"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
我是如何到达那里的。仔细看堆栈跟踪:
Server stack trace:
at System.ServiceModel.Security.WSSecurityJan2004.WrappedKeyTokenEntry.CreateWrappedKeyToken(String id, String encryptionMethod, String carriedKeyName, SecurityKeyIdentifier unwrappingTokenIdentifier, Byte[] wrappedKey, SecurityTokenResolver tokenResolver)
at System.ServiceModel.Security.WSSecurityJan2004.WrappedKeyTokenEntry.ReadTokenCore(XmlDictionaryReader reader, SecurityTokenResolver tokenResolver)
at System.ServiceModel.Security.WSSecurityTokenSerializer.ReadTokenCore(XmlReader reader, SecurityTokenResolver tokenResolver)
at System.IdentityModel.Selectors.SecurityTokenSerializer.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver)
at System.ServiceModel.Security.WSSecurityOneDotZeroReceiveSecurityHeader.DecryptWrappedKey(XmlDictionaryReader reader)
at System.ServiceModel.Security.ReceiveSecurityHeader.ReadEncryptedKey(XmlDictionaryReader reader, Boolean processReferenceListIfPresent)
at System.ServiceModel.Security.ReceiveSecurityHeader.ExecuteFullPass(XmlDictionaryReader reader)
at System.ServiceModel.Security.StrictModeSecurityHeaderElementInferenceEngine.ExecuteProcessingPasses(ReceiveSecurityHeader securityHeader, XmlDictionaryReader reader)
at System.ServiceModel.Security.ReceiveSecurityHeader.Process(TimeSpan timeout, ChannelBinding channelBinding, ExtendedProtectionPolicy extendedProtectionPolicy)
at System.ServiceModel.Security.MessageSecurityProtocol.ProcessSecurityHeader(ReceiveSecurityHeader securityHeader, Message& message, SecurityToken requiredSigningToken, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
at System.ServiceModel.Security.AsymmetricSecurityProtocol.VerifyIncomingMessageCore(Message& message, String actor, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
at System.ServiceModel.Security.MessageSecurityProtocol.VerifyIncomingMessage(Message& message, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.ProcessReply(Message reply, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
我在 JetBrains dotPeek 的帮助下调试了 CreateWrappedKeyToken 方法,并看到它试图从证书中读取原始SKI并且它没有找到它。