问题描述
我想从.net c#客户端使用CXF Web服务。我们目前正在处理Java到Java的请求,并且通过ws-security(WSS4J库)保护SOAP信封。
我的问题是:如何实现C# WS-client产生与以下客户端Java代码相同的SOAP请求?
// doc是原始的SOAP信封用WSS4J
WSSecHeader secHeader = new WSSecHeader()处理;
secHeader.insertSecurityHeader(doc);
//添加带有密码摘要的用户名令牌
WSSecUsernameToken usrNameTok = new WSSecUsernameToken();
usrNameTok.setPasswordType(WSConstants.PASSWORD_DIGEST);
usrNameTok.setUserInfo( guest,psw_guest);
usrNameTok.prepare(doc);
usrNameTok.appendToHeader(secHeader);
//用客户端密钥
在信封主体上签名WSSecSignature sign = new WSSecSignature();
sign.setUserInfo( clientx509v1,psw_clientx509v1);
sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
DocumentsignedDoc = null;
sign.prepare(doc,sigCrypto,secHeader);
SignedDoc = sign.build(doc,sigCrypto,secHeader);
//使用服务器公钥
加密信封主体WSSecEncrypt crypto = new WSSecEncrypt();
crypto.setUserInfo( serverx509v1);
//构建加密的SOAP部分
String out = null;
DocumentcryptedDoc = crypto.build(signedDoc,encCrypto,secHeader);
返回encryptedDoc;
有人知道我在哪里可以找到Microsoft how-to或.net工作示例吗?
==============================编辑== =================================
谢谢你拉迪斯拉夫!我应用了您的建议,然后想到了这样的东西:
X509Certificate2 client_pk,server_cert;
client_pk =新的X509Certificate2(@ C:\x509\clientKey.pem, blablabla);
server_cert =新的X509Certificate2(@ C:\x509\server-cert.pfx, blablabla);
//创建绑定。
System.ServiceModel.WSHttpBinding myBinding = new WSHttpBinding();
myBinding.TextEncoding = ASCIIEncoding.UTF8;
myBinding.MessageEncoding = WSMessageEncoding.Text;
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
myBinding.Security.Message.AlgorithmSuite =
System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128;
//禁用凭据协商和
//安全上下文的建立。
myBinding.Security.Message.NegotiateServiceCredential = false;
myBinding.Security.Message.EstablishSecurityContext = false;
//创建端点地址。
EndpointAddress ea =
新EndpointAddress(新Uri( http://bla.bla.bla),
EndpointIdentity.CreateDnsIdentity( issuer)));
//在通道工厂上配置用户名凭据
UsernameClientCredentials凭据= new UsernameClientCredentials(new
UsernameInfo( superadmin, secret)));
//创建客户端。
PersistenceClient客户=新的PersistenceClient(myBinding,ea);
client.Endpoint.Contract.ProtectionLevel =
System.Net.Security.ProtectionLevel.EncryptAndSign;
//将ClientCredentials替换为UsernameClientCredentials
client.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
client.Endpoint.Behaviors.Add(credentials);
//指定用于认证客户端的证书。
client.ClientCredentials.ClientCertificate.Certificate = client_pk;
//指定服务的默认证书。
client.ClientCredentials.ServiceCertificate.DefaultCertificate = server_cert;
//开始使用客户端。
client.Open();
clientProxyNetwork []响应= client.GetAllNetwork();
结果,我(服务器端)收到以下CXF异常:
java.security.SignatureException:签名不匹配。
在sun.security.x509.X509CertImpl.verify(X509CertImpl.java:421)
在sun.security.provider.certpath.BasicChecker.verifySignature(BasicChecker.java:133)
在sun .security.provider.certpath.BasicChecker.check(BasicChecker.java:112)
在sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:117)
因此,似乎是一个关键的jks-> pem转换问题...还是我上面的客户端代码中缺少某些内容?
最后,解决方案是对整个用户名令牌进行加密和签名。至于互操作性,必须在cxf中激活ws寻址,并且需要在c#中进行自定义绑定。达到目的的自定义绑定基本上是
AsymmetricSecurityBindingElement abe =
(AsymmetricSecurityBindingElement)SecurityBindingElement。
CreateMutualCertificateBindingElement(MessageSecurityVersion。
WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
Wcf在每个ws寻址元素上签名,因此必须在服务器端执行相同的操作。 / p>
I would like to consume a CXF web-service from a .net c# client. We are currently working with java-to-java requests and we protect SOAP envelopes through ws-security (WSS4J library).
My question is: how can I implement a C# WS-client which produces the same SOAP requests as the following client-side java code?
//doc is the original SOAP envelope to process with WSS4J
WSSecHeader secHeader = new WSSecHeader();
secHeader.insertSecurityHeader(doc);
//add username token with password digest
WSSecUsernameToken usrNameTok = new WSSecUsernameToken();
usrNameTok.setPasswordType(WSConstants.PASSWORD_DIGEST);
usrNameTok.setUserInfo("guest",psw_guest);
usrNameTok.prepare(doc);
usrNameTok.appendToHeader(secHeader);
//sign the envelope body with client key
WSSecSignature sign = new WSSecSignature();
sign.setUserInfo("clientx509v1", psw_clientx509v1);
sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
Document signedDoc = null;
sign.prepare(doc, sigCrypto, secHeader);
signedDoc = sign.build(doc, sigCrypto, secHeader);
//encrypt envelope body with server public key
WSSecEncrypt encrypt = new WSSecEncrypt();
encrypt.setUserInfo("serverx509v1");
// build the encrypted SOAP part
String out = null;
Document encryptedDoc = encrypt.build(signedDoc, encCrypto, secHeader);
return encryptedDoc;
Does anybody know where I could find a microsoft how-to or a .net working example?
================================ EDIT ====================================
Thank you Ladislav! I applied your suggestions and I came up with something like:
X509Certificate2 client_pk, server_cert;
client_pk = new X509Certificate2(@"C:\x509\clientKey.pem", "blablabla");
server_cert = new X509Certificate2(@"C:\x509\server-cert.pfx", "blablabla");
// Create the binding.
System.ServiceModel.WSHttpBinding myBinding = new WSHttpBinding();
myBinding.TextEncoding = ASCIIEncoding.UTF8;
myBinding.MessageEncoding = WSMessageEncoding.Text;
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
myBinding.Security.Message.AlgorithmSuite =
System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128;
// Disable credential negotiation and the establishment of
// a security context.
myBinding.Security.Message.NegotiateServiceCredential = false;
myBinding.Security.Message.EstablishSecurityContext = false;
// Create the endpoint address.
EndpointAddress ea =
new EndpointAddress(new Uri("http://bla.bla.bla"),
EndpointIdentity.CreateDnsIdentity("issuer"));
// configure the username credentials on the channel factory
UsernameClientCredentials credentials = new UsernameClientCredentials(new
UsernameInfo("superadmin", "secret"));
// Create the client.
PersistenceClient client = new PersistenceClient(myBinding, ea);
client.Endpoint.Contract.ProtectionLevel =
System.Net.Security.ProtectionLevel.EncryptAndSign;
// replace ClientCredentials with UsernameClientCredentials
client.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
client.Endpoint.Behaviors.Add(credentials);
// Specify a certificate to use for authenticating the client.
client.ClientCredentials.ClientCertificate.Certificate = client_pk;
// Specify a default certificate for the service.
client.ClientCredentials.ServiceCertificate.DefaultCertificate = server_cert;
// Begin using the client.
client.Open();
clientProxyNetwork[] response = client.GetAllNetwork();
As a result I get (server-side) the following CXF exception:
java.security.SignatureException: Signature does not match.
at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:421)
at sun.security.provider.certpath.BasicChecker.verifySignature(BasicChecker.java:133)
at sun.security.provider.certpath.BasicChecker.check(BasicChecker.java:112)
at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate (PKIXMasterCertPathValidator.java:117)
Therefore it seems a key jks->pem conversion problem... Or am I am missing something in the client-code above?
Well, in the end the solution is to encrypt and sign the whole username token. As for the interoperability, the ws addressing must be activated in cxf and a custom binding in c# is needed. The custom binding that did the trick is basically
AsymmetricSecurityBindingElement abe =
(AsymmetricSecurityBindingElement)SecurityBindingElement.
CreateMutualCertificateBindingElement(MessageSecurityVersion.
WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
Wcf signs each ws addressing element, therefore the same must be done server side.
这篇关于.net WCF-CXF / WSS4j互操作性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!