Search code examples
cosign-api

Error code 706 when signing PDF using Web Agent in Java


When testing the Web Agent sample in Java, I am getting an error reply

<?xml version="1.0" encoding="utf-8"?>
<response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" type="error">
  <Error>
    <returnCode>706</returnCode>
    <errorMessage>Value cannot be null.
Parameter name: s</errorMessage>
  </Error>
</response>

I followed the Ruby example in the CoSign Web Agent samples and the documentation

I have used the demo.pdf file provided in the sample.

This is the XML (from test app) sent in the POST request (the <content></content> has the Base64 encoded PDF, but omitted because of length).

<?xml version="1.0" encoding="utf-8" ?>
<request>
  <Logic>
    <allowAdHoc>true</allowAdHoc>
    <workingMode>pull</workingMode>
    <enforceReason>false</enforceReason>
  </Logic>
  <Url>
    <finishURL>http://localhost:64956/retrieveSignedFile.aspx</finishURL>
  </Url>
  <Document>
    <fileID>1234567890</fileID>
    <contentType>pdf</contentType>
    <content>{BASE64 encoded pdf content}</content>
  </Document>
</request>

The following is the java code I have used:

public class CoSignTest {
    private static final String INPUT = "D:\\tmp\\demo.pdf";
    private static final String PRECONTENT = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
            "<request>\n" +
            "  <Logic>\n" +
            "    <allowAdHoc>true</allowAdHoc>\n" +
            "    <workingMode>pull</workingMode>\n" +
            "    <enforceReason>false</enforceReason>\n" +
            "  </Logic>\n" +
            "  <Url>\n" +
            "    <finishURL>http://localhost:64956/retrieveSignedFile.aspx</finishURL>\n" +
            "  </Url>\n" +
            "  <Document>\n" +
            "    <fileID>1234567890</fileID>\n" +
            "    <contentType>pdf</contentType>\n" +
            "    <content>";
    private static final String POSTCONTENT = "</content>\n" +
            "  </Document>\n" +
            "</request>";
    private static final String POST_URL = "https://webagentdev.arx.com/Sign/UploadFileToSign";
    private static final String PULL_URL = "https://webagentdev.arx.com/Sign/DownloadSignedFileG";
    public static final int TIMEOUT = 300000;

    public static void main(String[] args) throws Exception {
        InputStream is = new FileInputStream(INPUT);
        String content = PRECONTENT + new String(Base64.encodeBase64(loadResource(is)), "UTF-8") + POSTCONTENT;
        System.out.println(content);
        String reply = new String(sendDocForProcessing(URLEncoder.encode(content, "UTF-8")));
        System.out.println(reply);
        System.out.println("DONE");
    }

    private static String sendDocForProcessing(String content) throws Exception {
        HttpClient client = null;
        HttpMethodBase method = null;
        SimpleHttpConnectionManager mgr = new SimpleHttpConnectionManager();
        String reply = "";
        try {
            mgr.getParams().setConnectionTimeout(TIMEOUT);
            mgr.getParams().setSoTimeout(TIMEOUT);
            client = new HttpClient(mgr);
            method = new PostMethod(POST_URL);
            method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(1, false));
            method.getParams().setParameter("http.socket.timeout", TIMEOUT);
            client.getHttpConnectionManager().getParams().setConnectionTimeout(TIMEOUT);
            client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
            method.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            method.getParams().setParameter("inputXML", content);
            client.executeMethod(method);
            reply = new String(method.getResponseBody());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(method != null) {
                method.releaseConnection();
            }
            client = null;
            mgr.shutdown();
        }
        if (isSigningSuccessful(reply)) {
            return reply;
        } else {
            throw new Exception("Failed in signing the document. Error: " + reply);
        }
    }

    private static boolean isSigningSuccessful(String reply) throws ParserConfigurationException, IOException, SAXException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse(new ByteArrayInputStream(reply.getBytes()));
        Element elem = doc.getDocumentElement();
        String type = elem.getAttribute("type");
        return !"error".equals(type);
    }


    public static byte[] loadResource(InputStream in) {
        if (in == null) {
            return new byte[0];
        }
        try {
            int indice, tempIndice;
            byte[] tempArr;
            byte[] mainArr = new byte[0];
            byte[] byteArr = new byte[65535];
            for (indice = 0; (indice = in.read(byteArr)) > 0;) {
                tempIndice = mainArr.length + indice;
                tempArr = new byte[tempIndice];
                System.arraycopy(mainArr, 0, tempArr, 0, mainArr.length);
                System.arraycopy(byteArr, 0, tempArr, mainArr.length, indice);
                mainArr = tempArr;
            }
            in.close();
            return mainArr;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new byte[0];
    }
}

Solution

  • Thanks for adding your Java code. Note that the HttpClient instance is configured incorrectly and as a result the http-post request is sent empty. Take a look at the modifications I did in your sendDocForProcessing function in order to properly post the XML content:

    private static String sendDocForProcessing(String content) throws Exception {
        HttpClient client = null;
        PostMethod method = null;
        String reply = "";
        try {
            client = new HttpClient();
            method = new PostMethod(POST_URL);
            method.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            NameValuePair[] data = { new NameValuePair("inputXML", content) };
            method.setRequestBody(data);
            client.executeMethod(method);
            reply = method.getResponseBodyAsString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(method != null) {
                method.releaseConnection();
            }
        }
        if (isSigningSuccessful(reply)) {
            return reply;
        } else {
            throw new Exception("Failed in signing the document. Error: " + reply);
        }
    }
    

    The content passed to the above function should not be URL-encoded as it is already done by the HttpClient library.

    In addition, when analyzing the response, I suggest you to check the value of the returnCode element rather than the type property. The response is always of type 'error'. Also note that the function name isSigningSuccessful is misleading as this stage is still prior to the act of signing.