#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2012
    Posts
    2
    Rep Power
    0

    Exclamation Java class call works only after CF restart then errors


    I am consuming a web service, not providing one. I have reached the point where I have the whole thing working, but a Java class call only works once through a ColdFusion "createObject" invokation.

    Still need help. System: Windows Server 2003 with ColdFusion 9 single server installation.

    I used Apache's wss4J library and wrote a simple Java class as the entry point. The custom Java class simply takes the complete SOAP message as a String argument, passes the String to the wss4j DateStamp class, then passes the resulting SOAP parts object to the signature class, then the encryption class. It then returns the signed and encrypted SOAP envelope, which has been converted from a document (SOAP parts) to a String by the PrettyDocumentToString function.

    All of this works and I get a well-formed SOAP envelope with security header and signed, encrypted body. The problem is that, after restarting the ColdFusion service (single server install on Windows Server 2003), it all works one time, but subsequent runs result in an error occurring within the wss4j signature code. I have even used Winmerge to compare the entire ColdFusion9 directory immediately after restart, immediately after the 1st run, and immediately after the 2nd run. The only differences were in the log files. There were differences in the ColdFusion9\lib\neo-datasource.xml file, but only in the order of a couple of datasource descriptors, not the content.

    Below is the code and stack trace:
    >writeOutputs and writeDumps are only for visualization during debugging.

    ColdFusion calling script:
    Code:
        <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 class:
    Code:
        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 Error:

    Code:
    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>");
    Stack Trace:

    Code:
        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

    Obviously, something is missing from org.apache.ws.security.message.DOMCallbackLookup.getElements.The code feeding it is:

    Code:
     
    return callbackLookup.getElements(part.getName(),part.getNamespace());
    I can't seem to figure out why it works the first time when called from CF, but fails with this error on subsequent runs.
  2. #2
  3. No Profile Picture
    Moderator

    Join Date
    Jun 2002
    Location
    Raleigh, NC
    Posts
    5,279
    Rep Power
    968
    My first guess is that it's because you're using static properties in a number of places. I'd try modifying your Java class to eliminate the use of static properties, then see if it works. If it does, you know that's it.
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2012
    Posts
    2
    Rep Power
    0

    ANSWER Found


    Found that I had actually invoked the class incorrectly for its structure. After washing out my brain, I changed the CF code to

    Code:
    encSOAP=createObject("java", "ProcessIDSRSSOAP");
    encSOAP.init(variables.fileContent);
    encDoc=encSOAP.getencryptedSOAP();
    and I changed the java clall so the constructor accepts the single String argument provided by the init line in the CF script. I added a true setter and getter to the class and everything works fine.

IMN logo majestic logo threadwatch logo seochat tools logo