Got this installed and discovered all my cameras today. Great binding, thanks for all your hard work!
I wanted to share some notes from my experience in case they help other folks in the future.
First, my Synology serves only HTTPS on port 5001 with an ACME generated certificate from a self-signed root ca (via a local stepca acme server).
I have installed the root certificate on all my end user devices (laptops, tablets, phones, etc.); however, I needed to make it available as a Java Key Store to the OpenHab JVM for the binding to be able to communicate with Surveillance Station over HTTPS.
Note, that there were no error messages and the binding showed as âOnlineâ. I found the problem by increasing the log level to debug (offending debug log message at the end of the post).
To do this, I took my public certificate and ran Java keytool
like this:
keytool -import -alias myopenhab -file /var/tmp/public.crt -storetype JKS -keystore /var/tmp/public.truststore.jks
Note, that you will be prompted for a password; however, this does not appear to be used by the JVM for truststores (as you will see below I donât pass the password to the OH2 JVM).
Then I mounted it into my OpenHab docker container and told the JVM to use it:
-v /opt/openhab/public.truststore.jks:/etc/public.truststore.jks:ro
-e JAVA_OPTS='-Djavax.net.ssl.trustStore=/etc/public.truststore.jks'
If you are not using Docker, you can set the JAVA_OPTS by modifying openhab2/runtime/bin/setenv
.
Unfortunately, you are not done yet. The Surveillance Station binding was initially configured with an IP address. However, you need to use the domain name in order to look-up and verify the serverâs key in the trust store. Unless your domain name is public, you need to tell Docker about your DNS server and possibly any DNS search suffixes:
--dns 192.168.1.1
--dns-search private.foo
To check if your domain name resolves you can do this:
$ docker exec -it <OH_CONTAINER_ID> /bin/bash
<container>$ apt update
<container>$ apt install iputils-ping
<container>$ ping synology.private.foo
<container>$ ping: synology.private.foo: Name or service not known
Now you can reconfigure the binding to use the domain name (e.g. synology.private.foo
) and everything should work as expected.
If you are having trouble getting it to work, I found this SSLPoke utility from Atlassian made it very easy to try different trust stores and JVM arguments (I ran it from inside the OpenHab docker container to reduce the number of moving parts).
e.g.
$ docker exec -it <OH_CONTAINER_ID> /bin/bash
<container>$ apt update
<container>$ apt install wget
<container>$ wget https://confluence.atlassian.com/kb/files/779355358/779355357/1/1441897666313/SSLPoke.class
<container>$ java SSLPoke synology.private.foo 5001
Some suggestions for improving the plugin:
- Detect connection failures due to misconfigured SSL and log warnings or errors
- Relabel the configuration input box as hostname or ip address
- Allow ignoring invalid (e.g. unverifiable) server certificates (useful for testing)
The only other thing I noticed, is that every time I go to edit the bridge thing settings, it shows my custom username and then quickly changes to âadminâ. I checked the thing file on disk and it has the correct username and password. This was very strange.
Hereâs the debug message that I saw in the logs indicating there was a problem with the SSL setup:
javax.net.ssl.SSLHandshakeException: General SSLEngine problem at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1523) ~[?:1.8.0_232] at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:528) ~[?:1.8.0_232] at sun.security.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1197) ~[?:1.8.0_232] at sun.security.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1165) ~[?:1.8.0_232] at javax.net.ssl.SSLEngine.wrap(SSLEngine.java:509) ~[?:1.8.0_232] at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.flush(SslConnection.java:891) ~[?:?] at org.eclipse.jetty.io.WriteFlusher.flush(WriteFlusher.java:422) ~[?:?] at org.eclipse.jetty.io.WriteFlusher.completeWrite(WriteFlusher.java:378) ~[?:?] at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.lambda$fill$1(SslConnection.java:669) ~[?:?] at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:782) [bundleFile:9.4.20.v20190813] at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:918) [bundleFile:9.4.20.v20190813] at java.lang.Thread.run(Thread.java:748) [?:1.8.0_232] Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[?:1.8.0_232] at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1709) ~[?:1.8.0_232] at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:320) ~[?:1.8.0_232] at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:312) ~[?:1.8.0_232] at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1640) ~[?:1.8.0_232] at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223) ~[?:1.8.0_232] at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1039) ~[?:1.8.0_232] at sun.security.ssl.Handshaker$1.run(Handshaker.java:972) ~[?:1.8.0_232] at sun.security.ssl.Handshaker$1.run(Handshaker.java:969) ~[?:1.8.0_232] at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_232] at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1461) ~[?:1.8.0_232] at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:526) ~[?:?] at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:128) ~[?:?] at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:73) ~[?:?] at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:133) ~[?:?] at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:154) ~[?:?] at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) ~[?:?] at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) ~[?:?] at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:426) ~[?:?] at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:320) ~[?:?] at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:158) ~[?:?] at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) ~[?:?] at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) ~[?:?] at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:367) ~[?:?] ... 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 sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397) ~[?:1.8.0_232] at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302) ~[?:1.8.0_232] at sun.security.validator.Validator.validate(Validator.java:262) ~[?:1.8.0_232] at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:327) ~[?:1.8.0_232] at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:279) ~[?:1.8.0_232] at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:144) ~[?:1.8.0_232] at org.eclipse.smarthome.io.net.http.internal.ExtensibleTrustManagerImpl.checkServerTrusted(ExtensibleTrustManagerImpl.java:119) ~[?:?] at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1627) ~[?:1.8.0_232] at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223) ~[?:1.8.0_232] at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1039) ~[?:1.8.0_232] at sun.security.ssl.Handshaker$1.run(Handshaker.java:972) ~[?:1.8.0_232] at sun.security.ssl.Handshaker$1.run(Handshaker.java:969) ~[?:1.8.0_232] at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_232] at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1461) ~[?:1.8.0_232] at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:526) ~[?:?] at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:128) ~[?:?] at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:73) ~[?:?] at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:133) ~[?:?] at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:154) ~[?:?] at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) ~[?:?] at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) ~[?:?] at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:426) ~[?:?] at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:320) ~[?:?] at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:158) ~[?:?] at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) ~[?:?] at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) ~[?:?] at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:367) ~[?:?] ... 3 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[?:1.8.0_232] at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[?:1.8.0_232] at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) ~[?:1.8.0_232] at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392) ~[?:1.8.0_232] at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302) ~[?:1.8.0_232] at sun.security.validator.Validator.validate(Validator.java:262) ~[?:1.8.0_232] at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:327) ~[?:1.8.0_232] at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:279) ~[?:1.8.0_232] at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:144) ~[?:1.8.0_232] at org.eclipse.smarthome.io.net.http.internal.ExtensibleTrustManagerImpl.checkServerTrusted(ExtensibleTrustManagerImpl.java:119) ~[?:?] at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1627) ~[?:1.8.0_232] at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223) ~[?:1.8.0_232] at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1039) ~[?:1.8.0_232] at sun.security.ssl.Handshaker$1.run(Handshaker.java:972) ~[?:1.8.0_232] at sun.security.ssl.Handshaker$1.run(Handshaker.java:969) ~[?:1.8.0_232] at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_232] at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1461) ~[?:1.8.0_232] at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:526) ~[?:?] at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:128) ~[?:?] at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:73) ~[?:?] at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:133) ~[?:?] at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:154) ~[?:?] at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) ~[?:?] at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) ~[?:?] at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:426) ~[?:?] at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:320) ~[?:?] at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:158) ~[?:?] at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) ~[?:?] at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) ~[?:?] at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) ~[?:?] at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:367) ~[?:?]