Unable to POST on a REST API using https

Our company uses ERP software to keep track production and they expose an API for use. I use ignition and the API to interface with the ERP software which is hosted locally we recently updated software with a new requirement of all request to use https . I use the httpClient to send my payload over but it raises an exception attached below. I am cannot POST to the server and I believe SSL has something to do with it. My question is if this has to do with Ignition SSL certificate not being valid and so the server then rejects the connection, or is Ignition refusing to connect to the server based on the servers SSL certificate?

Any help is greatly appreciated.

example script:

query = 'SELECT 1'
client = system.net.httpClient()
url = "https://172.16.10.109/odyssey/api/FetchData/SQL"
companyID = system.tag.read('[default]Odyssey/CompanyID').value
params = {
  "SQLQuery": query,
  "Page": 1,
  "BatchSize": 1800,
  "CompanyID": companyID,
  "APIKey":"the api key"
}
client.post(url, data=params)

resulting in

Traceback (most recent call last):
  File "<input>", line 12, in <module>
	at com.inductiveautomation.ignition.common.script.builtin.http.JythonHttpClient.send(JythonHttpClient.java:94)
	at com.inductiveautomation.ignition.common.script.builtin.http.JythonHttpClient.post(JythonHttpClient.java:309)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
java.io.IOException: java.io.IOException: Unable to POST https://172.16.10.109/odyssey/api/FetchData/SQL
	at org.python.core.Py.JavaError(Py.java:552)
	at org.python.core.Py.JavaError(Py.java:543)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)
	at org.python.core.PyObject.__call__(PyObject.java:438)
	at org.python.core.PyMethod.instancemethod___call__(PyMethod.java:237)
	at org.python.core.PyMethod.__call__(PyMethod.java:228)
	at org.python.pycode._pyx40.f$0(<input>:12)
	at org.python.pycode._pyx40.call_function(<input>)
	at org.python.core.PyTableCode.call(PyTableCode.java:171)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1614)
	at org.python.core.Py.exec(Py.java:1658)
	at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:276)
	at org.python.util.InteractiveInterpreter.runcode(InteractiveInterpreter.java:131)
	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:605)
	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$ConsoleWorker.doInBackground(JythonConsole.java:593)
	at java.desktop/javax.swing.SwingWorker$1.call(Unknown Source)
	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
	at java.desktop/javax.swing.SwingWorker.run(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.io.IOException: Unable to POST https://172.16.10.109/odyssey/api/FetchData/SQL
	at com.inductiveautomation.ignition.common.script.builtin.http.JythonHttpClient.send(JythonHttpClient.java:94)
	at com.inductiveautomation.ignition.common.script.builtin.http.JythonHttpClient.post(JythonHttpClient.java:309)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:188)
	... 19 more
Caused by: java.io.IOException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.net.http/jdk.internal.net.http.HttpClientImpl.send(Unknown Source)
	at java.net.http/jdk.internal.net.http.HttpClientFacade.send(Unknown Source)
	at com.inductiveautomation.ignition.common.script.builtin.http.JythonHttpClient.send(JythonHttpClient.java:92)
	... 25 more
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.base/sun.security.ssl.Alert.createSSLException(Unknown Source)
	at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source)
	at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source)
	at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source)
	at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(Unknown Source)
	at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(Unknown Source)
	at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(Unknown Source)
	at java.base/sun.security.ssl.SSLHandshake.consume(Unknown Source)
	at java.base/sun.security.ssl.HandshakeContext.dispatch(Unknown Source)
	at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(Unknown Source)
	at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(Unknown Source)
	at java.base/java.util.ArrayList.forEach(Unknown Source)
	at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate.lambda$executeTasks$3(Unknown Source)
	at java.net.http/jdk.internal.net.http.HttpClientImpl$DelegatingExecutor.execute(Unknown Source)
	at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate.executeTasks(Unknown Source)
	at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate.doHandshake(Unknown Source)
	at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Reader.processData(Unknown Source)
	at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Reader$ReaderDownstreamPusher.run(Unknown Source)
	at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SynchronizedRestartableTask.run(Unknown Source)
	at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(Unknown Source)
	at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(Unknown Source)
	... 3 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.base/sun.security.validator.PKIXValidator.doBuild(Unknown Source)
	at java.base/sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
	at java.base/sun.security.validator.Validator.validate(Unknown Source)
	at java.base/sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
	... 22 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source)
	at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
	at java.base/java.security.cert.CertPathBuilder.build(Unknown Source)
	... 28 more
Traceback (most recent call last):
  File "<input>", line 12, in <module>
	at com.inductiveautomation.ignition.common.script.builtin.http.JythonHttpClient.send(JythonHttpClient.java:94)
	at com.inductiveautomation.ignition.common.script.builtin.http.JythonHttpClient.post(JythonHttpClient.java:309)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
java.io.IOException: java.io.IOException: Unable to POST https://172.16.10.109/odyssey/api/FetchData/SQL

It's this one. Your server certificate is either self-signed or signed by an internal CA, and you need to add that certificate or CA to Ignition's trust store.

https://docs.inductiveautomation.com/display/DOC81/Security+Certificates#SecurityCertificates-AddingSecurityCertificatesintoKeyStores

2 Likes

Oh alright. Thanks. I'm on 8.0.12 does the document linked still hold true for that?

I think so: Adding Security Certificates into KeyStores - Ignition User Manual 8.0 - Ignition Documentation

Where you're actually running this script is important too. Your stack traces show that it's in a Client or Designer, so you'd have to add the certificate to the client trust store. If you'll ultimately run it on the Gateway then you'll have to add it there as well.

Great thanks. Much appreciated

Sorry, @Kevin.Herron, dropping the certificates into %ignition install%/data/certificates/supplemental still yields the error. I'm getting the certificate from exporting it from chrome and then placing it in the directory. Is that an acceptable way for getting the certificate? I also placed the certificate into ~/.ignition/clientlauncher-data/certificates .

If you got it from Chrome you may have only gotten the leaf, not the root.

You also would want to restart the Gateway or Client/Designer after adding it just in case.

Yup restarted the server same behaviour. Leaf vs root implies that I don't get the full certificate from chrome?

Don't know without looking at it. If it's self-signed it's just one certificate and the leaf is the root. Otherwise there's a certificate chain and I'm not sure what you got and imported into Ignition.

It is a self signed certificate.

Can you upload it here? or DM it to me? There shouldn't be anything confidential about it.

-----BEGIN CERTIFICATE-----
MIIDtDCCApygAwIBAgIQFlk/g8VN19VkFM3TAhH84TANBgkqhkiG9w0BAQsFADBH
MUUwQwYDVQQDDDxUaGUgb3JpZ2luYWwgY2VydGlmaWNhdGUgcHJvdmlkZWQgYnkg
dGhlIHNlcnZlciBpcyB1bnRydXN0ZWQwHhcNMjIwMTIzMjAyNDMwWhcNMjMwMTIz
MjAyNDMwWjAoMSYwJAYDVQQDEx1PZHlzc2V5LVNlcnZlci5sZXRoaXJvbi5sb2Nh
bDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANJtLO6sx9Bc+ri9TiP+
yMpcpw+klvMx0bsm8PzQzb8CeliadZlxPc97TylSCXp26w6iydoyQGg7BaiLA2eI
tc1hWh+Tgqdv9VO6mV3WIgAxzOK52IEz0q9q46aoWpf3BTmYLFagZKeU3rbc9xT5
I0EIkPe1gG6ew5JU6wLu42/FM1Zhzq2aERVIqUnEElkKDR+9M3LcTtCK6BOSIQVr
yr3IUG1Qc2lOXf3D/SOER5KOy47WNFHJMqnPKDw7iaI3TDDwwJrL5Lhtfz4jUg+i
PS+2j4NIHpd1wEmpfNgdkD9oaLglo97bpK7lq7dEhrGQ9fXHbHfw/9yWk1YL5YfQ
CFcCAwEAAaOBujCBtzALBgNVHQ8EBAMCBaAwHQYDVR0OBBYEFDoK1MY3w+m1BGuy
en4IpFZYSwjWMB8GA1UdIwQYMBaAFDoK1MY3w+m1BGuyen4IpFZYSwjWMB0GA1Ud
JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATBJBgNVHREEQjBAoB8GCSsGAQQBgjcZ
AaASBBD6+n7QQNd9QYgvwOOOu2eAgh1PZHlzc2V5LVNlcnZlci5sZXRoaXJvbi5s
b2NhbDANBgkqhkiG9w0BAQsFAAOCAQEAnjnQPvLoVI6FJycspJBN3BNQaDJa5x4r
OjpQEBlfEh8L2zDagmIuZr+kdmyUkKV1BWQvFGePTreXxrVeoE5d88maXs9KDdIU
HfQpcCR8kwtTGxzzzo9w20ocCj5CZ9MZxSaVvUOOlZj/jrP6aS+QtzLJxN39OGf4
I9tli6lRP6LWc1k4S6FWD7xdP+zci0oIPut23y/zariIJTlFGZ7Og0TRZ+XIckiU
+5UmVpSc0F+9WxkbKBCWcunpCJVgEP3jF94RM9gdZl3lp2Kt5P3qiM6nj9/JClNK
HRvGXNTmEUr1wCjbWRFEl6vUwPWzcUQipa695hBvp+6YRUtHjneWbA==
-----END CERTIFICATE-----

Okay, well, I haven't seen this before:

Seems suspicious.

Also this certificate was issued using the DNS name, so you would also have to access this sever using that same DNS name, not the IP address as you're doing.

edit: that text ("The original certificate provided...") is literally embedded in the certificate as the issuer name. Seems wrong.

Hm, yes I wondered about that. I believe this certificate was generated from our ERP software automatically but that's according to one of my co-workers. So would issuing a new certificate be beneficial?

Might be necessary. You can try using the bypass_cert_validation parameter for now... system.net.httpClient - Ignition User Manual 8.1 - Ignition Documentation

Ok thanks. The error changed now Caused by: javax.net.ssl.SSLHandshakeException: No subject alternative names matching IP address 172.16.10.109 found likely as you said because of the dns name.