From ec7c3a528ffa9e9ffdc0474f3bddd70d4b6737df Mon Sep 17 00:00:00 2001 From: lolodomo Date: Sun, 20 Jun 2021 19:36:34 +0200 Subject: [PATCH] [remoteopenhab] Avoid registering conflicting filters for SSE connection (#10870) * [remoteopenhab] Avoid registering conflicting filters for SSE connection Signed-off-by: Laurent Garnier * Remove default constructor Signed-off-by: Laurent Garnier * Review comment: declare the hostname verifier in a variable Signed-off-by: Laurent Garnier --- .../rest/RemoteopenhabRestClient.java | 43 ++++++++++++++----- .../RemoteopenhabStreamingRequestFilter.java | 23 +++++++--- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabRestClient.java b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabRestClient.java index b6ebe5d1a33..f43becaf11c 100644 --- a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabRestClient.java +++ b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabRestClient.java @@ -273,21 +273,44 @@ public class RemoteopenhabRestClient { private SseEventSource createEventSource(String restSseUrl) { String credentialToken = restSseUrl.startsWith("https:") || authenticateAnyway ? this.credentialToken : ""; + + RemoteopenhabStreamingRequestFilter filter; + boolean filterRegistered = clientBuilder.getConfiguration() + .isRegistered(RemoteopenhabStreamingRequestFilter.class); + if (filterRegistered) { + filter = clientBuilder.getConfiguration().getInstances().stream() + .filter(instance -> instance instanceof RemoteopenhabStreamingRequestFilter) + .map(instance -> (RemoteopenhabStreamingRequestFilter) instance).findAny().orElseThrow(); + } else { + filter = new RemoteopenhabStreamingRequestFilter(); + } + filter.setCredentialToken(restSseUrl, credentialToken); + Client client; // Avoid a timeout exception after 1 minute by setting the read timeout to 0 (infinite) if (trustedCertificate) { - client = clientBuilder.sslContext(httpClient.getSslContextFactory().getSslContext()) - .hostnameVerifier(new HostnameVerifier() { - @Override - public boolean verify(@Nullable String hostname, @Nullable SSLSession session) { - return true; - } - }).readTimeout(0, TimeUnit.SECONDS) - .register(new RemoteopenhabStreamingRequestFilter(credentialToken)).build(); + HostnameVerifier alwaysValidHostname = new HostnameVerifier() { + @Override + public boolean verify(@Nullable String hostname, @Nullable SSLSession session) { + return true; + } + }; + if (filterRegistered) { + client = clientBuilder.sslContext(httpClient.getSslContextFactory().getSslContext()) + .hostnameVerifier(alwaysValidHostname).readTimeout(0, TimeUnit.SECONDS).build(); + } else { + client = clientBuilder.sslContext(httpClient.getSslContextFactory().getSslContext()) + .hostnameVerifier(alwaysValidHostname).readTimeout(0, TimeUnit.SECONDS).register(filter) + .build(); + } } else { - client = clientBuilder.readTimeout(0, TimeUnit.SECONDS) - .register(new RemoteopenhabStreamingRequestFilter(credentialToken)).build(); + if (filterRegistered) { + client = clientBuilder.readTimeout(0, TimeUnit.SECONDS).build(); + } else { + client = clientBuilder.readTimeout(0, TimeUnit.SECONDS).register(filter).build(); + } } + SseEventSource eventSource = eventSourceFactory.newSource(client.target(restSseUrl)); eventSource.register(this::onEvent, this::onError, this::onComplete); return eventSource; diff --git a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabStreamingRequestFilter.java b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabStreamingRequestFilter.java index 8e9b03eef5a..37d58b03951 100644 --- a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabStreamingRequestFilter.java +++ b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/rest/RemoteopenhabStreamingRequestFilter.java @@ -13,6 +13,7 @@ package org.openhab.binding.remoteopenhab.internal.rest; import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; import javax.ws.rs.client.ClientRequestContext; import javax.ws.rs.client.ClientRequestFilter; @@ -21,6 +22,8 @@ import javax.ws.rs.core.MultivaluedMap; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Inserts Authorization and Cache-Control headers for requests on the streaming REST API. @@ -30,20 +33,28 @@ import org.eclipse.jdt.annotation.Nullable; @NonNullByDefault public class RemoteopenhabStreamingRequestFilter implements ClientRequestFilter { - private final String credentialToken; + private final Logger logger = LoggerFactory.getLogger(RemoteopenhabStreamingRequestFilter.class); - public RemoteopenhabStreamingRequestFilter(String credentialToken) { - this.credentialToken = credentialToken; - } + private final ConcurrentHashMap credentialTokens = new ConcurrentHashMap<>(); @Override public void filter(@Nullable ClientRequestContext requestContext) throws IOException { if (requestContext != null) { MultivaluedMap headers = requestContext.getHeaders(); - if (!credentialToken.isEmpty()) { - headers.putSingle(HttpHeaders.AUTHORIZATION, "Basic " + credentialToken); + String credentialToken = credentialTokens.get(requestContext.getUri().toString()); + if (credentialToken != null) { + if (!credentialToken.isEmpty()) { + headers.putSingle(HttpHeaders.AUTHORIZATION, "Basic " + credentialToken); + } + } else { + logger.warn("No credential token set! uri={}", requestContext.getUri()); } headers.putSingle(HttpHeaders.CACHE_CONTROL, "no-cache"); } } + + public void setCredentialToken(String target, String token) { + logger.debug("Set credential token. target={}, token={}", target, token); + credentialTokens.put(target, token); + } }