简体   繁体   中英

How to consume a Java Metro Web Service using Username Authentication with a Symmetric key in a Gsoap client?

I am doing research on interoperability between secure web services. The security has to be done on the message level ONLY. So far I have managed to get WCF and WSIT/Metro working together using certificates. Now I am trying to do the same thing using gSoap, but so far I have had no luck.

I have succesfully managed to generate a header file from the Java service WSDL using wsdl2h and I was able to generate the necessary classes using soapcpp2. By following the gsoap documentation, the WSSE and WSA plugins should be configured correctly and indeed if I do some sniffing in Wireshark, I see that the Gsoap client sends a request with a security header and the WS-Addressing fields (To, Action, MessageID, ReplyTo).

The Java service is configured to use Username Authentication with a Symmetric Key using the 3DES algorithm, username authentication token and a Lax security header layout.

The certificates are in the Glassfish keystore and truststore and have been exported and converted to PEM files for usage in gSoap.

This is my code for the C++ application:

    #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;
    }

As far as I am aware, what I am doing is adding the timestamp, the certificate, the username and password, then I encrypt the body with a dummy DES key and I sign the message with my own private key. Then I make the call...

However this is not working, what I get as output is:

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

GlassFish gives a stack trace:

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

I suppose the root of the problem is that the EncryptedKey is null according to the service but I have no idea which key that would be or why it would be null.

So my question is: is it possible to consume a secure Metro service from Gsoap, if so what am I doing wrong? What am I missing?

Thanks!

Have you tried asking your question on the gSOAP Yahoo group? It's at http://tech.groups.yahoo.com/group/gsoap/ . No promises; I'm struggling with a similar problem (different service, but gSOAP to Java Apache Axis with WSSE), and have only had a little help from that group.

By the way, there is a patch for gSOAP to enable getting back full error messages, instead of the "no detail" string. It's in this message: http://tech.groups.yahoo.com/group/gsoap/message/19031

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM