如何在ColdFusion中对SOAP请求BODY进行数字签名?

时间:2012-07-23 11:43:56

标签: web-services soap coldfusion digital-signature webservices-client

对我而言:我需要使用提供程序颁发​​的证书对来自ColdFusion客户端应用程序的SOAP请求体进行数字签名和加密。我还需要解密响应才能处理它。

我搜索了几天没发现任何东西。我找到了引用其他语言的信息,但在ColdFusion中没有任何内容。如果无法通过ColdFusion语言API本地执行此操作,有人可以帮助我通过'createObject()'函数或您可能拥有的任何其他方法调用正确的Java或.net类吗?

17SEP2012 - 附加信息:

更多信息:在我查看代码时发布时间超时。这是完整的帖子:

我正在使用网络服务,而不提供网络服务。我已经达到了整个工作的程度,但它只能通过ColdFusion“createObject”调用一次。

仍然需要帮助。系统:安装了ColdFusion 9单服务器的Windows Server 2003。

我使用了Apache的wss4J库并编写了一个简单的Java类作为入口点。自定义Java类只是将完整的SOAP消息作为String参数,将String传递给wss4j DateStamp类,然后将生成的SOAP部件对象传递给签名类,然后传递给加密类。然后它返回已签名和加密的SOAP信封,该信封已通过PrettyDocumentToString函数从文档(SOAP部分)转换为String。

所有这些都有效,我得到一个带有安全标头和签名加密主体的SOAP信封。问题是,在重新启动ColdFusion服务(Windows Server 2003上的单个服务器安装)之后,它都可以运行一次,但后续运行会导致wss4j签名代码中发生错误。我甚至使用Winmerge在重新启动后立即比较整个ColdFusion9目录,在第一次运行后立即比较,并在第二次运行后立即进行比较。唯一的区别在于日志文件。 ColdFusion9 \ lib \ neo-datasource.xml文件存在差异,但只有几个数据源描述符的顺序,而不是内容。

下面是代码和堆栈跟踪:

  

writeOutputs和writeDumps仅用于调试期间的可视化。

ColdFusion调用脚本:

<cfscript>
    variables.tempPath = getDirectoryFromPath(getCurrentTemplatePath());
    variables.filePath = tempPath & "ASI_source_request_example.xml";
    variables.fileContent = FileRead(filePath);

writeOutput("FILECONTENT: <br>");
writeOutput("variables.fileContent);
writeDump(var="#variables.fileContent#", format="html", output="#expandPath('./')#_DUMP-OUTPUT.htm");

    variables.encSOAP=createobject("java","ProcessIDSRSSOAP").runProcess(fileContent);

writeOutput("<br><br>encSOAP: <br>");
writeOutput(variables.encSOAP);
writeDump(var="#variables.encSOAP#", format="html", output="#expandPath('./')#_DUMP-OUTPUT.htm");
</cfscript>

Java类:

import java.io.FileReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.ws.security.SOAPConstants;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSEncryptionPart;
import org.apache.ws.security.WSSConfig;
import org.apache.ws.security.common.SOAPUtil;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.components.crypto.CryptoFactory;
import org.apache.ws.security.message.WSSecEncrypt;
import org.apache.ws.security.message.WSSecHeader;
import org.apache.ws.security.message.WSSecSignature;
import org.apache.ws.security.message.WSSecTimestamp;
import org.apache.ws.security.util.WSSecurityUtil;
import org.w3c.dom.Document;

public class ProcessIDSRSSOAP {
    private static Crypto crypto = null;
    private static Properties properties = new Properties();
    private static String user = "";
    private static String cryptoPwd = "";
    private static WSSecSignature builder = new WSSecSignature();
    private static SOAPConstants soapConstants = null;
    private final WSSecHeader secHeader = new WSSecHeader();
    private Document tsDoc = null;
    private Document signedDoc = null;
    private Document encryptedDoc = null;

    private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory
            .getLog(ProcessIDSRSSOAP.class);

    public ProcessIDSRSSOAP() throws Exception {
        WSSConfig.init();
    }

    /*
     * public static void main(String[] args) throws Exception {
     * ProcessIDSRSSOAP processor = new ProcessIDSRSSOAP();
     * processor.runProcess(args[0]); }
     */

    public String runProcess(String inDoc) throws Exception {
        // ProcessIDSRSSOAP processor = new ProcessIDSRSSOAP();
        // LOG.debug(inDoc);
        Class<ProcessIDSRSSOAP> thisClass = ProcessIDSRSSOAP.class;
        ClassLoader thisLoader = thisClass.getClassLoader();
        URL propertiesURL = thisLoader.getResource("crypto.properties");
        String propertiesPath = propertiesURL.getPath();
        propertiesPath = propertiesPath.replaceAll("%20", " ");
        properties.load(new FileReader(propertiesPath));
        user = properties
                .getProperty("org.apache.ws.security.crypto.merlin.keystore.alias");
        cryptoPwd = properties
                .getProperty("org.apache.ws.security.crypto.merlin.keystore.password");
        crypto = CryptoFactory.getInstance("crypto.properties");
        builder.setUserInfo(user, cryptoPwd);
        builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
        SOAPUtil.toSOAPPart(inDoc.trim());
        Document PKIDoc = processDoc(inDoc);
        String PKIDocString = org.apache.ws.security.util.XMLUtils
                .PrettyDocumentToString(PKIDoc);
        LOG.debug(PKIDocString);
        return PKIDocString;
    }

    /**
     * @param SOAPMsg
     *            The entire SOAP message as a type String
     * @throws Exception
     */
    public Document processDoc(String SOAPMsg) throws Exception {
        tsDoc = timestampMSG(SOAPMsg);// Time stamp the SOAP String and make it
                                        // a Document type.
        secHeader.insertSecurityHeader(tsDoc);// Insert the security header.
        soapConstants = WSSecurityUtil.getSOAPConstants(tsDoc
                .getDocumentElement());
        signedDoc = signBody(tsDoc);// Send the Document on for signing.
        encryptedDoc = encryptBody(signedDoc);
        return encryptedDoc;
    }

    /**
     * @param msg
     *            The entire SOAP message as a type String
     * @throws Exception
     */
    public Document timestampMSG(String msg) throws Exception {
        Document doc = SOAPUtil.toSOAPPart(msg);
        WSSecHeader secHeader = new WSSecHeader();
        secHeader.insertSecurityHeader(doc);

        WSSecTimestamp timestamp = new WSSecTimestamp();
        timestamp.setTimeToLive(300);
        Document createdDoc = timestamp.build(doc, secHeader);
        return createdDoc;
    }

    /**
     * @param doc
     *            Expects a SOAP message as a type Document
     * @throws Exception
     */
    public Document signBody(Document doc) throws Exception {
        List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
        WSEncryptionPart encP = new WSEncryptionPart(soapConstants
                .getBodyQName().getLocalPart(), soapConstants.getEnvelopeURI(),
                "");
        parts.add(encP);
        builder.setParts(parts);
        Document signedDoc = builder.build(doc, crypto, secHeader);
        return signedDoc;
    }

    public Document encryptBody(Document doc) throws Exception {
        SOAPConstants soapConstants = WSSecurityUtil.getSOAPConstants(doc
                .getDocumentElement());
        WSSecEncrypt encrypt = new WSSecEncrypt();
        encrypt.setUserInfo(user, cryptoPwd);
        encrypt.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);

        WSSecHeader secHeader = new WSSecHeader();
        secHeader.insertSecurityHeader(doc);

        List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
        WSEncryptionPart encP = new WSEncryptionPart(soapConstants
                .getBodyQName().getLocalPart(), // define the body
                soapConstants.getEnvelopeURI(), "");
        parts.add(encP);
        encrypt.setParts(parts);
        Document encryptedDoc = encrypt.build(doc, crypto, secHeader);
        return encryptedDoc;
    }
}

ColdFusion错误:

Signature creation failed (Cannot setup signature data structure)  


The error occurred in G:/Inetpub/wwwroot/SOAP/index.cfm: line 14

12 : writeDump(var="#variables.fileContent#", format="html", output="#expandPath('./')#_DUMP-OUTPUT.htm");
13 : 
14 :    variables.encSOAP=createobject("java","ProcessIDSRSSOAP").runProcess(fileContent);
15 : 
16 : writeOutput("<br><br>encSOAP: <br>");

堆栈追踪:

at cfindex2ecfm1134068877.runPage(G:/Inetpub/wwwroot/SOAP/index.cfm:14) 


org.apache.ws.security.WSSecurityException: Signature creation failed (Cannot setup signature data structure)
    at org.apache.ws.security.message.WSSecSignatureBase.addReferencesToSign(WSSecSignatureBase.java:191)
    at org.apache.ws.security.message.WSSecSignature.addReferencesToSign(WSSecSignature.java:409)
    at org.apache.ws.security.message.WSSecSignature.build(WSSecSignature.java:381)
    at ProcessIDSRSSOAP.signBody(ProcessIDSRSSOAP.java:118)
    at ProcessIDSRSSOAP.processDoc(ProcessIDSRSSOAP.java:85)
    at ProcessIDSRSSOAP.runProcess(ProcessIDSRSSOAP.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at coldfusion.runtime.java.JavaProxy.invoke(JavaProxy.java:97)
    at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2360)
    at cfindex2ecfm1134068877.runPage(G:\Inetpub\wwwroot\SOAP\index.cfm:14)
    at coldfusion.runtime.CfJspPage.invoke(CfJspPage.java:231)
    at coldfusion.tagext.lang.IncludeTag.doStartTag(IncludeTag.java:416)
    at coldfusion.filter.CfincludeFilter.invoke(CfincludeFilter.java:65)
    at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:381)
    at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:48)
    at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40)
    at coldfusion.filter.PathFilter.invoke(PathFilter.java:94)
    at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:70)
    at coldfusion.filter.BrowserDebugFilter.invoke(BrowserDebugFilter.java:79)
    at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)
    at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38)
    at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:46)
    at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38)
    at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
    at coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62)
    at coldfusion.CfmServlet.service(CfmServlet.java:200)
    at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89)
    at jrun.servlet.FilterChain.doFilter(FilterChain.java:86)
    at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42)
    at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46)
    at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
    at jrun.servlet.FilterChain.service(FilterChain.java:101)
    at jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:106)
    at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42)
    at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:286)
    at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543)
    at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203)
    at jrunx.scheduler.ThreadPool$DownstreamMetrics.invokeRunnable(ThreadPool.java:320)
    at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428)
    at jrunx.scheduler.ThreadPool$UpstreamMetrics.invokeRunnable(ThreadPool.java:266)
    at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)
Caused by: java.lang.NullPointerException
    at org.apache.ws.security.message.DOMCallbackLookup.getElements(DOMCallbackLookup.java:94)
    at org.apache.ws.security.util.WSSecurityUtil.findElements(WSSecurityUtil.java:267)
    at org.apache.ws.security.message.WSSecSignatureBase.addReferencesToSign(WSSecSignatureBase.java:156)
    ... 43 more

显然,org.apache.ws.security.message.DOMCallbackLookup.getElements缺少某些内容。 它的代码是:

return callbackLookup.getElements(part.getName(),part.getNamespace());

我似乎无法弄清楚为什么它从CF调用时第一次工作,但在后续运行中失败并出现此错误。

2 个答案:

答案 0 :(得分:1)

实际问题是我的函数调用被反转了。我颠倒了块的顺序

signedDoc = signBody(tsDoc);// Send the Document on for signing. encryptedDoc = encryptBody(signedDoc);

encryptedDoc = encryptBody(signedDoc); signedDoc = signBody(tsDoc);// Send the Document on for signing.

并且有效。

答案 1 :(得分:0)

你需要添加一个处理程序,看看这里,因为我相信这与你想要实现的类似:http://milanchandnacf.blogspot.co.uk/2011/09/adding-handler-to-coldfusion-web.html