]> git.basschouten.com Git - openhab-addons.git/commitdiff
[vizio] Improve handling of TV's self-signed certificate (#14429)
authormlobstein <michael.lobstein@gmail.com>
Tue, 21 Feb 2023 14:58:48 +0000 (08:58 -0600)
committerGitHub <noreply@github.com>
Tue, 21 Feb 2023 14:58:48 +0000 (15:58 +0100)
Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>
bundles/org.openhab.binding.vizio/README.md
bundles/org.openhab.binding.vizio/src/main/java/org/openhab/binding/vizio/internal/VizioHandlerFactory.java
bundles/org.openhab.binding.vizio/src/main/java/org/openhab/binding/vizio/internal/communication/VizioCommunicator.java
bundles/org.openhab.binding.vizio/src/main/java/org/openhab/binding/vizio/internal/communication/VizioTlsTrustManagerProvider.java [deleted file]
bundles/org.openhab.binding.vizio/src/main/java/org/openhab/binding/vizio/internal/console/VizioCommandExtension.java
bundles/org.openhab.binding.vizio/src/main/java/org/openhab/binding/vizio/internal/handler/VizioHandler.java

index 7c72f7b0ffa748890138506a5338240ebe5313fc..008072c06639548e7decd5451a2d5b6e81644899 100644 (file)
@@ -134,7 +134,7 @@ If an app that is in the JSON database fails to start when selected, try adjusti
 A current list of `APP_ID`'s can be found at http://hometest.buddytv.netdna-cdn.com/appservice/vizio_apps_prod.json
 and `NAME_SPACE` &amp; `MESSAGE` values needed can be found at http://hometest.buddytv.netdna-cdn.com/appservice/app_availability_prod.json
 
-If there is an error in the user supplied `appListJson`, the thing will fail to start and display a CONFIGURATION_PENDING message.
+If there is an error in the user supplied `appListJson`, the thing will fail to start and display a CONFIGURATION_ERROR message.
 If all text in `appListJson` is removed (set to null) and the thing configuration saved, the binding will restore `appListJson` from the binding's JSON db.
 
 ## Full Example
index 1967fb4f9479477c2b83e0b499193affe5913dba..2246218deea24be97569e86c9948ab96ca7d034f 100644 (file)
@@ -16,7 +16,6 @@ import static org.openhab.binding.vizio.internal.VizioBindingConstants.SUPPORTED
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.client.HttpClient;
 import org.openhab.binding.vizio.internal.appdb.VizioAppDbService;
 import org.openhab.binding.vizio.internal.handler.VizioHandler;
 import org.openhab.core.io.net.http.HttpClientFactory;
@@ -39,7 +38,7 @@ import org.osgi.service.component.annotations.Reference;
 @Component(service = ThingHandlerFactory.class, configurationPid = "binding.vizio")
 public class VizioHandlerFactory extends BaseThingHandlerFactory {
 
-    private final HttpClient httpClient;
+    private final HttpClientFactory httpClientFactory;
     private final VizioStateDescriptionOptionProvider stateDescriptionProvider;
     private final String vizioAppsJson;
 
@@ -47,7 +46,7 @@ public class VizioHandlerFactory extends BaseThingHandlerFactory {
     public VizioHandlerFactory(final @Reference HttpClientFactory httpClientFactory,
             final @Reference VizioStateDescriptionOptionProvider provider,
             final @Reference VizioAppDbService vizioAppDbService) {
-        this.httpClient = httpClientFactory.getCommonHttpClient();
+        this.httpClientFactory = httpClientFactory;
         this.stateDescriptionProvider = provider;
         this.vizioAppsJson = vizioAppDbService.getVizioAppsJson();
     }
@@ -62,7 +61,7 @@ public class VizioHandlerFactory extends BaseThingHandlerFactory {
         ThingTypeUID thingTypeUID = thing.getThingTypeUID();
 
         if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
-            VizioHandler handler = new VizioHandler(thing, httpClient, stateDescriptionProvider, vizioAppsJson);
+            VizioHandler handler = new VizioHandler(thing, httpClientFactory, stateDescriptionProvider, vizioAppsJson);
             return handler;
         }
 
index 34ff83de38f5a1ad6d4386bbacca04c5f90fc74c..632aa573ed9b44a42c42d251c1a60fa0076cc958 100644 (file)
@@ -196,7 +196,7 @@ public class VizioCommunicator {
      * @throws VizioException
      *
      */
-    public PairingStart starPairing(String deviceName, int deviceId) throws VizioException {
+    public PairingStart startPairing(String deviceName, int deviceId) throws VizioException {
         return fromJson(
                 putCommand(urlStartPairing,
                         String.format("{ \"DEVICE_NAME\": \"%s\", \"DEVICE_ID\": \"%d\" }", deviceName, deviceId)),
diff --git a/bundles/org.openhab.binding.vizio/src/main/java/org/openhab/binding/vizio/internal/communication/VizioTlsTrustManagerProvider.java b/bundles/org.openhab.binding.vizio/src/main/java/org/openhab/binding/vizio/internal/communication/VizioTlsTrustManagerProvider.java
deleted file mode 100644 (file)
index e825c19..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Copyright (c) 2010-2023 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.vizio.internal.communication;
-
-import java.net.MalformedURLException;
-import java.security.cert.CertificateException;
-
-import javax.net.ssl.X509ExtendedTrustManager;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.openhab.core.io.net.http.PEMTrustManager;
-import org.openhab.core.io.net.http.TlsTrustManagerProvider;
-import org.openhab.core.io.net.http.TrustAllTrustManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Provides a {@link PEMTrustManager} to allow secure connections to a Vizio TV that uses self signed
- * certificates.
- *
- * @author Christoph Weitkamp - Initial Contribution
- * @author Michael Lobstein - Adapted for Vizio binding
- */
-@NonNullByDefault
-public class VizioTlsTrustManagerProvider implements TlsTrustManagerProvider {
-    private final String hostname;
-
-    private final Logger logger = LoggerFactory.getLogger(VizioTlsTrustManagerProvider.class);
-
-    public VizioTlsTrustManagerProvider(String hostname) {
-        this.hostname = hostname;
-    }
-
-    @Override
-    public String getHostName() {
-        return hostname;
-    }
-
-    @Override
-    public X509ExtendedTrustManager getTrustManager() {
-        try {
-            logger.trace("Use self-signed certificate downloaded from Vizio TV.");
-            return PEMTrustManager.getInstanceFromServer("https://" + getHostName());
-        } catch (CertificateException | MalformedURLException e) {
-            logger.debug("An unexpected exception occurred - returning a TrustAllTrustManager: {}", e.getMessage(), e);
-        }
-        return TrustAllTrustManager.getInstance();
-    }
-}
index 69cfb41bd3538c05d8163843fbab35aa584cb360..5a55582b3ad6ba436771a766ff0763405c347b2b 100644 (file)
@@ -107,7 +107,7 @@ public class VizioCommandExtension extends AbstractConsoleCommandExtension {
                             Random rng = new Random();
 
                             int pairingDeviceId = rng.nextInt(100000);
-                            int pairingToken = communicator.starPairing(args[2], pairingDeviceId).getItem()
+                            int pairingToken = communicator.startPairing(args[2], pairingDeviceId).getItem()
                                     .getPairingReqToken();
                             if (pairingToken != -1) {
                                 handler.setPairingDeviceId(pairingDeviceId);
index 1bb3d7ae1db2d6584caa9563a0061d2615ade6c3..1bb0975b41c08ea040fb11749263854be2534fe5 100644 (file)
@@ -25,11 +25,11 @@ import java.util.concurrent.TimeUnit;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.openhab.binding.vizio.internal.VizioConfiguration;
 import org.openhab.binding.vizio.internal.VizioException;
 import org.openhab.binding.vizio.internal.VizioStateDescriptionOptionProvider;
 import org.openhab.binding.vizio.internal.communication.VizioCommunicator;
-import org.openhab.binding.vizio.internal.communication.VizioTlsTrustManagerProvider;
 import org.openhab.binding.vizio.internal.dto.app.CurrentApp;
 import org.openhab.binding.vizio.internal.dto.applist.VizioApp;
 import org.openhab.binding.vizio.internal.dto.applist.VizioApps;
@@ -40,7 +40,7 @@ import org.openhab.binding.vizio.internal.dto.inputlist.InputList;
 import org.openhab.binding.vizio.internal.dto.power.PowerMode;
 import org.openhab.binding.vizio.internal.enums.KeyCommand;
 import org.openhab.core.config.core.Configuration;
-import org.openhab.core.io.net.http.TlsTrustManagerProvider;
+import org.openhab.core.io.net.http.HttpClientFactory;
 import org.openhab.core.library.types.NextPreviousType;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.library.types.PercentType;
@@ -53,12 +53,11 @@ import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingStatus;
 import org.openhab.core.thing.ThingStatusDetail;
 import org.openhab.core.thing.binding.BaseThingHandler;
+import org.openhab.core.thing.util.ThingWebClientUtil;
 import org.openhab.core.types.Command;
 import org.openhab.core.types.RefreshType;
 import org.openhab.core.types.StateOption;
 import org.openhab.core.types.UnDefType;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceRegistration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -74,11 +73,11 @@ import com.google.gson.JsonSyntaxException;
 @NonNullByDefault
 public class VizioHandler extends BaseThingHandler {
     private final Logger logger = LoggerFactory.getLogger(VizioHandler.class);
-    private final HttpClient httpClient;
+    private final HttpClientFactory httpClientFactory;
+    private @Nullable HttpClient httpClient;
     private final VizioStateDescriptionOptionProvider stateDescriptionProvider;
     private final String dbAppsJson;
 
-    private @Nullable ServiceRegistration<?> serviceRegistration;
     private @Nullable ScheduledFuture<?> refreshJob;
     private @Nullable ScheduledFuture<?> metadataRefreshJob;
 
@@ -97,13 +96,13 @@ public class VizioHandler extends BaseThingHandler {
     private boolean powerOn = false;
     private boolean debounce = true;
 
-    public VizioHandler(Thing thing, HttpClient httpClient,
+    public VizioHandler(Thing thing, HttpClientFactory httpClientFactory,
             VizioStateDescriptionOptionProvider stateDescriptionProvider, String vizioAppsJson) {
         super(thing);
-        this.httpClient = httpClient;
+        this.httpClientFactory = httpClientFactory;
         this.stateDescriptionProvider = stateDescriptionProvider;
         this.dbAppsJson = vizioAppsJson;
-        this.communicator = new VizioCommunicator(httpClient, EMPTY, -1, EMPTY);
+        this.communicator = new VizioCommunicator(httpClientFactory.getCommonHttpClient(), EMPTY, -1, EMPTY);
     }
 
     @Override
@@ -127,13 +126,22 @@ public class VizioHandler extends BaseThingHandler {
             host = "[" + host + "]";
         }
 
-        this.communicator = new VizioCommunicator(httpClient, host, config.port, authToken != null ? authToken : EMPTY);
-
-        // register trustmanager service to allow httpClient to accept self signed cert from the Vizio TV
-        VizioTlsTrustManagerProvider tlsTrustManagerProvider = new VizioTlsTrustManagerProvider(
-                host + ":" + config.port);
-        serviceRegistration = FrameworkUtil.getBundle(getClass()).getBundleContext()
-                .registerService(TlsTrustManagerProvider.class.getName(), tlsTrustManagerProvider, null);
+        final String httpClientName = ThingWebClientUtil.buildWebClientConsumerName(thing.getUID(), null);
+        try {
+            httpClient = httpClientFactory.createHttpClient(httpClientName, new SslContextFactory.Client(true));
+            final HttpClient localHttpClient = this.httpClient;
+            if (localHttpClient != null) {
+                localHttpClient.start();
+                this.communicator = new VizioCommunicator(localHttpClient, host, config.port,
+                        authToken != null ? authToken : EMPTY);
+            }
+        } catch (Exception e) {
+            logger.error(
+                    "Long running HttpClient for Vizio handler {} cannot be started. Creating Handler failed. Exception: {}",
+                    httpClientName, e.getMessage(), e);
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
+            return;
+        }
 
         if (authToken == null) {
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING,
@@ -363,11 +371,14 @@ public class VizioHandler extends BaseThingHandler {
             this.metadataRefreshJob = null;
         }
 
-        ServiceRegistration<?> localServiceRegistration = serviceRegistration;
-        if (localServiceRegistration != null) {
-            // remove trustmanager service
-            localServiceRegistration.unregister();
-            serviceRegistration = null;
+        try {
+            HttpClient localHttpClient = this.httpClient;
+            if (localHttpClient != null) {
+                localHttpClient.stop();
+            }
+            this.httpClient = null;
+        } catch (Exception e) {
+            logger.debug("Unable to stop Vizio httpClient. Exception: {}", e.getMessage(), e);
         }
     }