如何在Gsoap客户端中使用带有对称密钥的用户名身份验证来使用Java Metro Web Service?

时间:2012-03-12 15:39:16

标签: java c++ web-services security gsoap

我正在研究安全Web服务之间的互操作性。安全性必须仅在消息级别上完成。到目前为止,我已经设法使用证书使WCF和WSIT / Metro协同工作。现在我正在尝试使用gSoap做同样的事情,但到目前为止我没有运气。

我已经成功地使用wsdl2h从Java服务WSDL生成头文件,并且我能够使用soapcpp2生成必要的类。通过遵循gsoap文档,WSSE和WSA插件应该正确配置,如果我在Wireshark中进行一些嗅探,我看到Gsoap客户端发送带有安全头和WS-Addressing的请求字段(To,Action,MessageID,ReplyTo)。

Java服务配置为使用3DES算法,用户名认证令牌和Lax安全标头布局,使用带有对称密钥的用户名认证。

证书位于Glassfish密钥库和信任库中,并已导出并转换为PEM文件,以便在gSoap中使用。

这是我的C ++应用程序代码:

    #include <cstdlib>
    #include <iostream>
    #include "soapNewWebServicePortBindingProxy.h"
    #include "NewWebServicePortBinding.nsmap"
    #include "wsseapi.h"
    #include "wsaapi.h"

    using namespace std;

    /*
     * 
     */
    int main(int argc, char** argv) {
        static char DES_KEY[20] =
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
        /* SET UP */
        NewWebServicePortBinding proxy;
        proxy.soap = soap_new1(SOAP_XML_CANONICAL | SOAP_XML_INDENT);
        soap_register_plugin(proxy.soap, soap_wsa);
        soap_register_plugin(proxy.soap, soap_wsse);  
        ns1__hello req;
        ns1__helloResponse resp;
        req.name = new std::string("derpenstein");  

        /* ADD WS-SECURITY ELEMENTS  */    
        soap_wsse_add_Security(proxy.soap);
        soap_wsse_add_Signature(proxy.soap);
        soap_wsse_add_Timestamp(proxy.soap, NULL, 300);

        //OpenSSL_add_all_algorithms();
        FILE *fd = fopen("gsoappublic.pem", "r");
        FILE *fpriv = fopen("gsoapprivate.pem", "r");

        X509 *cert = PEM_read_X509(fd, NULL, NULL, NULL);

        EVP_PKEY *privkey = NULL;
        EVP_PKEY *pubkey = NULL;

        privkey = PEM_read_PrivateKey(fpriv, NULL, NULL, (void*)"changeit");

        if (!privkey) {
            cout << "error getting private key" << endl;
            ERR_print_errors_fp(stderr);
            return -1;
        }

        pubkey = X509_get_pubkey(cert);
        if (!pubkey) {
            cout << "error getting public key from certificate" << endl;
        }
        fclose(fd);
        fclose(fpriv);

        if (soap_wsse_encrypt_body(proxy.soap, SOAP_MEC_ENC_DES_CBC, DES_KEY, sizeof(DES_KEY))
         || soap_wsse_add_EncryptedKey(proxy.soap, "Cert", cert, NULL)
         || soap_wsse_add_UsernameTokenText(proxy.soap, "User", "test", "test")
         || soap_wsse_sign_body(proxy.soap, SOAP_SMD_SIGN_RSA_SHA1, privkey, 0)
         || soap_wsse_add_BinarySecurityTokenX509(proxy.soap, "X509Token", cert)
         || soap_wsse_add_KeyInfo_SecurityTokenReferenceX509(proxy.soap, "#X509Token")){
            soap_print_fault(proxy.soap, stderr);
        }

        /* ADD WS-ADDRESSING */
        soap_wsse_set_wsu_id(proxy.soap, "wsa5:From wsa5:To wsa5:ReplyTo wsa5:FaultTo wsa5:Action");  
        if (soap_wsa_request(proxy.soap, "uuid:5012354ad", "http://belgianguypc:8080/NewSecureService/NewWebService", "http://newsec.mince.org/NewWebService/helloRequest")
            || soap_wsa_add_ReplyTo(proxy.soap, "http://www.w3.org/2005/08/addressing/anonymous")) {
            soap_print_fault(proxy.soap, stderr);
        }


        /* MAKE THE CALL */
        int err = proxy.__ns1__hello(&req, &resp);
        if (err == SOAP_OK) {
            cout << "Success!";
            cout << resp.return_;
        }
        else {
            cout << "When sending:" << endl;
            soap_print_fault(proxy.soap, stderr);
            return -1;
        }

        return 0;
    }

据我所知,我正在做的是添加时间戳,证书,用户名和密码,然后我用虚拟DES密钥对身体进行加密,然后使用我自己的私钥对消息进行签名。然后我打电话......

然而这不起作用,我得到的输出是:

When sending:
SOAP 1.1 Fault: wsse:FailedCheck [no subcode]
"WSS1927: Error occurred while decrypting EncryptedKey"
Detail: [no detail]

GlassFish提供堆栈跟踪:

SEVERE: WSS1913: Key used to decrypt EncryptedKey cannot be null
SEVERE: WSS1927: Error occured while decrypting EncryptedKey
SEVERE: WSITPVD0035: Error in Verifying Security in Inbound Message.
com.sun.xml.wss.impl.WssSoapFaultException: WSS1927: Error occured while decrypting EncryptedKey
    at com.sun.xml.ws.security.opt.impl.util.SOAPUtil.newSOAPFaultException(SOAPUtil.java:158)
    at com.sun.xml.ws.security.opt.impl.incoming.EncryptedKey.getKey(EncryptedKey.java:354)
    at com.sun.xml.ws.security.opt.impl.incoming.KeySelectorImpl.resolveDirectReference(KeySelectorImpl.java:628)
    at com.sun.xml.ws.security.opt.impl.incoming.processor.SecurityTokenProcessor.processDirectReference(SecurityTokenProcessor.java:267)
    at com.sun.xml.ws.security.opt.impl.incoming.processor.SecurityTokenProcessor.resolveReference(SecurityTokenProcessor.java:143)
    at com.sun.xml.ws.security.opt.impl.incoming.processor.KeyInfoProcessor.processKeyInfo(KeyInfoProcessor.java:152)
    at com.sun.xml.ws.security.opt.impl.incoming.processor.KeyInfoProcessor.getKey(KeyInfoProcessor.java:132)
    at com.sun.xml.ws.security.opt.impl.incoming.EncryptedData.process(EncryptedData.java:156)
    at com.sun.xml.ws.security.opt.impl.incoming.EncryptedData.<init>(EncryptedData.java:113)
    at com.sun.xml.ws.security.opt.impl.incoming.SecurityRecipient.createMessage(SecurityRecipient.java:791)
    at com.sun.xml.ws.security.opt.impl.incoming.SecurityRecipient.validateMessage(SecurityRecipient.java:232)
    at com.sun.xml.wss.provider.wsit.WSITServerAuthContext.verifyInboundMessage(WSITServerAuthContext.java:586)
    at com.sun.xml.wss.provider.wsit.WSITServerAuthContext.validateRequest(WSITServerAuthContext.java:360)
    at com.sun.xml.wss.provider.wsit.WSITServerAuthContext.validateRequest(WSITServerAuthContext.java:263)
    at com.sun.enterprise.security.webservices.CommonServerSecurityPipe.processRequest(CommonServerSecurityPipe.java:173)
    at com.sun.enterprise.security.webservices.CommonServerSecurityPipe.process(CommonServerSecurityPipe.java:144)
    at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:119)
    at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:641)
    at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:600)
    at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:585)
    at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:482)
    at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:314)
    at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:608)
    at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:259)
    at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:162)
    at org.glassfish.webservices.JAXWSServlet.doPost(JAXWSServlet.java:145)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:232)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.io.IOException: Key used to decrypt EncryptedKey cannot be null
    at com.sun.xml.ws.security.opt.impl.enc.CryptoProcessor.decryptKey(CryptoProcessor.java:346)
    at com.sun.xml.ws.security.opt.impl.incoming.EncryptedKey.getKey(EncryptedKey.java:351)
    ... 51 more

我认为问题的根源是EncryptedKey根据服务为空,但我不知道它将是哪个键或为什么它将为null。

所以我的问题是:是否有可能从Gsoap使用安全的Metro服务,如果是这样,我做错了什么?我错过了什么?

谢谢!

1 个答案:

答案 0 :(得分:0)

您是否尝试过在gSOAP Yahoo群组中提问?它在http://tech.groups.yahoo.com/group/gsoap/。没有承诺;我正在努力解决类似的问题(不同的服务,但是使用WSSE的gSOAP到Java Apache Axis),并且只得到了该组的一点帮助。

顺便说一下,有一个gSOAP补丁可以恢复完整的错误消息,而不是&#34;没有细节&#34;串。它在此消息中:http://tech.groups.yahoo.com/group/gsoap/message/19031