[remoteopenhab] Avoid registering conflicting filters for SSE connection (#10870)

* [remoteopenhab] Avoid registering conflicting filters for SSE connection

Signed-off-by: Laurent Garnier <lg.hc@free.fr>

* Remove default constructor

Signed-off-by: Laurent Garnier <lg.hc@free.fr>

* Review comment: declare the hostname verifier in a variable

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo 2021-06-20 19:36:34 +02:00 committed by GitHub
parent 8d39e5b2ee
commit ec7c3a528f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 16 deletions

View File

@ -273,21 +273,44 @@ public class RemoteopenhabRestClient {
private SseEventSource createEventSource(String restSseUrl) { private SseEventSource createEventSource(String restSseUrl) {
String credentialToken = restSseUrl.startsWith("https:") || authenticateAnyway ? this.credentialToken : ""; 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; Client client;
// Avoid a timeout exception after 1 minute by setting the read timeout to 0 (infinite) // Avoid a timeout exception after 1 minute by setting the read timeout to 0 (infinite)
if (trustedCertificate) { if (trustedCertificate) {
client = clientBuilder.sslContext(httpClient.getSslContextFactory().getSslContext()) HostnameVerifier alwaysValidHostname = new HostnameVerifier() {
.hostnameVerifier(new HostnameVerifier() { @Override
@Override public boolean verify(@Nullable String hostname, @Nullable SSLSession session) {
public boolean verify(@Nullable String hostname, @Nullable SSLSession session) { return true;
return true; }
} };
}).readTimeout(0, TimeUnit.SECONDS) if (filterRegistered) {
.register(new RemoteopenhabStreamingRequestFilter(credentialToken)).build(); 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 { } else {
client = clientBuilder.readTimeout(0, TimeUnit.SECONDS) if (filterRegistered) {
.register(new RemoteopenhabStreamingRequestFilter(credentialToken)).build(); client = clientBuilder.readTimeout(0, TimeUnit.SECONDS).build();
} else {
client = clientBuilder.readTimeout(0, TimeUnit.SECONDS).register(filter).build();
}
} }
SseEventSource eventSource = eventSourceFactory.newSource(client.target(restSseUrl)); SseEventSource eventSource = eventSourceFactory.newSource(client.target(restSseUrl));
eventSource.register(this::onEvent, this::onError, this::onComplete); eventSource.register(this::onEvent, this::onError, this::onComplete);
return eventSource; return eventSource;

View File

@ -13,6 +13,7 @@
package org.openhab.binding.remoteopenhab.internal.rest; package org.openhab.binding.remoteopenhab.internal.rest;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.client.ClientRequestContext; import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter; 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.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; 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. * Inserts Authorization and Cache-Control headers for requests on the streaming REST API.
@ -30,20 +33,28 @@ import org.eclipse.jdt.annotation.Nullable;
@NonNullByDefault @NonNullByDefault
public class RemoteopenhabStreamingRequestFilter implements ClientRequestFilter { public class RemoteopenhabStreamingRequestFilter implements ClientRequestFilter {
private final String credentialToken; private final Logger logger = LoggerFactory.getLogger(RemoteopenhabStreamingRequestFilter.class);
public RemoteopenhabStreamingRequestFilter(String credentialToken) { private final ConcurrentHashMap<String, String> credentialTokens = new ConcurrentHashMap<>();
this.credentialToken = credentialToken;
}
@Override @Override
public void filter(@Nullable ClientRequestContext requestContext) throws IOException { public void filter(@Nullable ClientRequestContext requestContext) throws IOException {
if (requestContext != null) { if (requestContext != null) {
MultivaluedMap<String, Object> headers = requestContext.getHeaders(); MultivaluedMap<String, Object> headers = requestContext.getHeaders();
if (!credentialToken.isEmpty()) { String credentialToken = credentialTokens.get(requestContext.getUri().toString());
headers.putSingle(HttpHeaders.AUTHORIZATION, "Basic " + credentialToken); 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"); 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);
}
} }