API Endpoint Certs

When calling an API (in this case graphql) if I set the following, the call and response goes through OK:

client = system.net.httpClient(bypass_cert_validation=True)

However without bypassing the cert validation I see the following when posting:

caused by: sun.security.validator.validatorexception: pkix path building failed: sun.security.provider.certpath.suncertpathbuilderexception: unable to find valid certification path to requested target

As far as I have read, I need to get the cert from the endpoint and place it on the machine running Ignition. In which directory should that be placed?

Thanks,

Nick

See this for a starting point:

There's no specific file location; you'd need to scaffold an SSLContext with the appropriate cert installed.

I think you’ve mixed it up - he just needs to get the certificate and add it to the supplemental certs folder.

https://docs.inductiveautomation.com/display/DOC81/Adding+Security+Certificates+into+Keystores

Oh, yeah, you’re right; he’s not doing mutual TLS, just wants to trust the server. Nevermind then.

@Kevin.Herron following that instruction to place in supplemental certs I have placed the root certificate of the target endpoint (Kafka Lenses) into the folder as follows and restarted the service.

However, I still see the following. Is there some other action I need to do like import the cert using keytool?

java.util.concurrent.ExecutionException: java.util.concurrent.ExecutionException: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Thanks,

Nick

No, that should be it for Ignition 8.x. What scope are you testing your scripting call in? Adding it to the supplemental cert folder only brings it in for the gateway scope.

Right now I’m working in the script console to get it up to the point where I can get a response and learn how to parse through it. The end game will be on a gateway script timer or in a UDT.

This machine runs 8.1.13. Sorry if this is duplicate but its related to web sockets. What we are trying to do is have a way to get a filtered response from Kafka since the topic itself is terabyte size. The Lense SQL api allows this and I have it working in the google web socket tested.

Just working through the mechanics of making it work in the ignition environment.

Thanks,

Nick

Make a gateway message handler that delegates to a script module. In the designer script console, use system.util.sendRequest() to trigger your code and receive the result. The actual request to Kafka will then come from the gateway as you intend in the future, and will use its certificate store.

I am going to merge this thread into this:

The summary here is that by moving this to a gateway script (as opposed to running it all from the script console) overcomes the error named:

unable to find valid certification path to requested target

Thanks,

Nick

@PGriffith I have a different case now that does require the use of mutual TLS. As I read above the system.net.httpClient native to Ignition cannot do mTLS, is that correct?

My eventual target is in Java but for testing it is often convenient to get things working from the python script console first.

Thanks,

Nick

Correct, it's not supported.

It's more awkward than it should be even in pure Java, as you'll gather quickly from Google/StackOverflow posts.

Yeah, that is what I am seeing. Anyways, once I do get it figured out in Java, I'll post it back up here so the next person that comes along can use it for reference.

Here the SSL cert auto-renewal API that we are starting to work with requires mTLS.

Nick

1 Like

FWIW, this code here allows us to get through the SSL handshake successfully:

public class JavaHttpClientTest {
    public static void main(String[] args) {
        String appId = "";
        String commonName = "";
        String teamDL = "";
        String certPath = "";
        char certPass[] = "".toCharArray();
        try {
            String urlString = "";
            urlString = String.format(urlString+"?appID=%s&commonName=%s&teamDL=%s", appId, commonName, teamDL);
            System.out.println(urlString);

            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(new FileInputStream(certPath), certPass);

            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, certPass);

            SSLContext ctx = SSLContext.getInstance("TLSv1.3");
            ctx.init(keyManagerFactory.getKeyManagers(), null, null);

            HttpClient client = HttpClient.newBuilder().sslContext(ctx).build();
            HttpRequest request = HttpRequest.newBuilder().uri(URI.create(urlString)).GET().build();
            var response = client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).join();
            System.out.println(response.statusCode());
            System.out.println(response.body());
        } catch (Exception e) {
            System.out.println(e.getCause());
        }
    }
}

And to make the entire handshake work, it was also necessary to add the server cert to the JVM cacert store with the advice listed here. You can download the server cert directly from the browser, we downloaded in PKCS7 format.

Nick

1 Like

Hey Nick,

Just curious how exactly you are running this java script and how you were able to call it in ignition?

All code written in Java is executed in Ignition via module development. This post may be of some use if you're just getting started with modules:

How do you create your own MODL file - Module Development - Inductive Automation Forum

Ignition is also starting to add more training resources on how to build modules.

Nick