0
votes

I'm fairly new to Groovy & SoapUING. I hope someone can help me figure out and fix this error. Thanks!

What I'm trying to do: Iterate through each db row item in a table and use that as input to make a HTTPBuilder request (GET or POST) either as a query in path (add baseURL/path/hello) or through parameters(add baseURL/path?searchNode="hello"). The baseURL is something like this https://search-test-env.ser.com.

Where I'm getting stuck: When I try to post a request through HTTPBuilder.

Error: PKIX Path Building Failed

Other related information:

  • Using ReadyAPI to run the scripts. Code is in Groovy.
  • Recently imported the httpbuilder jar into ReadyAPI/lib folder along with some dependencies. Of the dependencies available with httpbuilder, ReadyAPI already had few so I only picked up the ones missing. Additional jar names: ojdbc6, ojdbc6_g, signpost-commonshttp4-1.2.1.1, ezmorph-1.0.6, json-lib-2.3-jdk15, xml-resolver-1.2, signpost-core-1.2.1.1, appengine-api-1.0-sdk-1.3.8, nekohtml-1.9.16, http-builder-0.7, http-builder-0.7-sources, http-builder-0.7-javadoc.
  • The Service works with a manual request without groovy (simple GET on the baseURL/path) and it also works with query by string or by parameter.
  • The certificate is already available in the Keystore. Tried using keytool (available in ReadyAPI/bin folder) command through cmd but receiving a filenotfound error). Tried to import into the ReadyAPI\jre\lib\security.

Code:

    def qryPrmRqstHTTPBldr( pBaseUrl, pPath, pQuery, pMethod ) {
    def ret = null
    def http = new HTTPBuilder()
    def meth

    if ( pMethod == 'GET') {
            meth = Method.GET
    }
    else if ( pMethod == 'POST') {
            meth = Method.POST
    }
    // perform a GET/POST request, expecting TEXT response
    http.request(pBaseUrl, meth, ContentType.TEXT) { req ->
        uri.path = pPath
        uri.query = pQuery
        /*
        headers.'User-Agent'         = 'Apache-HttpClient/4.5.1 (Java/1.8.0_66)'
        headers.'Host'               = 'xxx-xx-xxx.xxx.xxx'
        headers.'Accept-Encoding'    = 'gzip,deflate'
        headers.'Connection'         = 'Keep-Alive'
        */
        log.info System.getProperty("java.runtime.version")
        log.info System.getProperty("javax.net.ssl.trustStore")
        log.info System.getProperty("javax.net.ssl.keyStore")
        log.info System.getProperty("java.home")
        log.info System.getProperty("java.class.path")        

        // response handler for a success response code
        response.success = { resp, reader ->
                println "response status: ${resp.statusLine}"
                println 'Headers: -----------'

                ret = reader.getText()

                println 'Response data: -----'
                println ret
                println '--------------------'
            }
    }
      return ret
}

Running this code throws the PKIX Path Building Failed error (no stack trace available) and the content for each property:

System.getProperty("java.runtime.version") // 1.8.0_66-b17
System.getProperty("javax.net.ssl.trustStore") // null
System.getProperty("javax.net.ssl.keyStore") // null
System.getProperty("java.home") // c:\program files\smartbear\readyapi-1.6.0\jre 
System.getProperty("java.class.path") // C:\Program Files\SmartBear\ReadyAPI-1.6.0\.install4j\i4jruntime.jar;......
1

1 Answers

0
votes

The problem

PKIX path building failed error is thrown when your client can not construct a trust path to your server certificate. This basically means that in your trust store there isn't the certificate authority which issues the end entity certificate or a intermediate certificate for your server certificate; and it's needed to build the certificate chain.

In your case javax.net.ssl.trustStore it's not defined, due System.getProperty("javax.net.ssl.trustStore") is null; so from JSSE

  1. If the system property: javax.net.ssl.trustStore is defined, then the TrustManagerFactory attempts to find a file using the filename specified by that system property, and uses that file for the KeyStore. If the javax.net.ssl.trustStorePassword system property is also defined, its value is used to check the integrity of the data in the truststore before opening it. If javax.net.ssl.trustStore is defined but the specified file does not exist, then a default TrustManager using an empty keystore is created.

  2. If the javax.net.ssl.trustStore system property was not specified, then if the file <java-home>/lib/security/jssecacerts exists, that file is used. (See The Installation Directory for information about what refers to.)

  3. Otherwise, If the file <java-home>/lib/security/cacerts exists, that file is used.

The solution

Then to solve the problem you need to add the required certificates to JRE_HOME/lib/security/jssecacerts if exists or to JRE_HOME/lib/security/cacerts if not from the Java which are you using to run the Groovy scripts.

The correct way: Add the certificate authority of your server certificate in the trust store. Then make sure that your server correctly serves all certificate chain until CA: intermediate certificates (if needed) until the end entity server certificate.

The brute force way: If you've some problems setting up the trust store or you're not sure if the server is pushing the chain certificates... simply put directly the server certificate in the trust store. This is not the "purist" way but since you're only testing this will works.

How to do it

Download the CA server certificate and load it to the trust store using keytool with the follow command (the default password for cacerts is changeit):

keytool -import -alias <someAlias> -file <certificatePath> -keystore <trustStorePath>

Here there is one of my answers with a bit more detail about how to load the certificate.