Skip to content

Commit

Permalink
fix: add stomp v1.2 as supported protocol (#1697)
Browse files Browse the repository at this point in the history
* add stomp v1.2 as supported protocol

Signed-off-by: achmelo <a.chmelo@gmail.com>

* remove old classes from test

Signed-off-by: achmelo <a.chmelo@gmail.com>

* exclude ciphers, remove jetty server config

Signed-off-by: achmelo <a.chmelo@gmail.com>

* configurable subprotocol list

Signed-off-by: achmelo <a.chmelo@gmail.com>

* default value

Signed-off-by: achmelo <a.chmelo@gmail.com>
  • Loading branch information
achmelo committed Aug 12, 2021
1 parent 89ac5a2 commit d1057e0
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 84 deletions.
Expand Up @@ -168,25 +168,23 @@ public Set<String> publicKeyCertificatesBase64() {
return publicKeyCertificatesBase64;
}

@Bean
public SslContextFactory.Server jettySslContextFactory() {
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
if (StringUtils.isNotEmpty(keyStore)) {
sslContextFactory.setKeyStorePath(SecurityUtils.replaceFourSlashes(keyStore));
}
sslContextFactory.setProtocol(protocol);
sslContextFactory.setKeyStorePassword(keyStorePassword == null ? null : String.valueOf(keyStorePassword));
sslContextFactory.setKeyStoreType(keyStoreType);
sslContextFactory.setCertAlias(keyAlias);
sslContextFactory.setExcludeCipherSuites("^.*_(MD5|SHA|SHA1)$");

private void setTruststore(SslContextFactory sslContextFactory) {
if (StringUtils.isNotEmpty(trustStore)) {
sslContextFactory.setTrustStorePath(SecurityUtils.replaceFourSlashes(trustStore));
sslContextFactory.setTrustStoreType(trustStoreType);
sslContextFactory.setTrustStorePassword(trustStorePassword == null ? null : String.valueOf(trustStorePassword));
}
log.debug("jettySslContextFactory: {}", sslContextFactory.dump());
}

@Bean
@Qualifier("jettyClientSslContextFactory")
public SslContextFactory.Client jettyClientSslContextFactory() {
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
sslContextFactory.setProtocol(protocol);
sslContextFactory.setExcludeCipherSuites("^.*_(MD5|SHA|SHA1)$");
setTruststore(sslContextFactory);
log.debug("jettySslContextFactory: {}", sslContextFactory.dump());
sslContextFactory.setHostnameVerifier(secureHostnameVerifier());
if (!verifySslCertificatesOfServices) {
sslContextFactory.setTrustAll(true);
}
Expand Down

This file was deleted.

This file was deleted.

Expand Up @@ -21,7 +21,7 @@

/**
* Factory for provisioning web socket client
*
* <p>
* Manages the client lifecycle
*/
@Component
Expand All @@ -30,11 +30,11 @@ public class WebSocketClientFactory {

private final JettyWebSocketClient client;

public WebSocketClientFactory(SslContextFactoryProvider sslContextFactoryProvider) {
SslContextFactory.Server jettySslContextFactory = sslContextFactoryProvider.getSslFactory();
log.debug("Creating Jetty WebSocket client, with SslFactory: {} and SslContextFactoryProvider: {}",
jettySslContextFactory, sslContextFactoryProvider);
client = new JettyWebSocketClient(new WebSocketClient(new HttpClient(jettySslContextFactory)));
public WebSocketClientFactory(SslContextFactory.Client jettyClientSslContextFactory) {

log.debug("Creating Jetty WebSocket client, with SslFactory: {}",
jettyClientSslContextFactory);
client = new JettyWebSocketClient(new WebSocketClient(new HttpClient(jettyClientSslContextFactory)));
client.start();
}

Expand Down
Expand Up @@ -11,12 +11,18 @@

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.SubProtocolCapable;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import org.zowe.apiml.product.routing.*;
import org.zowe.apiml.product.routing.RoutedService;
import org.zowe.apiml.product.routing.RoutedServices;
import org.zowe.apiml.product.routing.RoutedServicesUser;

import javax.inject.Singleton;
import java.io.IOException;
Expand All @@ -33,7 +39,15 @@
@Component
@Singleton
@Slf4j
public class WebSocketProxyServerHandler extends AbstractWebSocketHandler implements RoutedServicesUser {
public class WebSocketProxyServerHandler extends AbstractWebSocketHandler implements RoutedServicesUser, SubProtocolCapable {

@Value("${server.webSocket.supportedProtocols:-}")
private List<String> subProtocols;

@Override
public List<String> getSubProtocols() {
return subProtocols;
}

private final Map<String, WebSocketRoutedSession> routedSessions;
private final Map<String, RoutedServices> routedServicesMap = new ConcurrentHashMap<>();
Expand Down Expand Up @@ -124,14 +138,15 @@ private String[] getUriParts(WebSocketSession webSocketSession) {
}

private void openWebSocketConnection(RoutedService service, ServiceInstance serviceInstance, Object uri,
String path, WebSocketSession webSocketSession) throws IOException {
String path, WebSocketSession webSocketSession) throws IOException {
String serviceUrl = service.getServiceUrl();
String targetUrl = getTargetUrl(serviceUrl, serviceInstance, path);

log.debug(String.format("Opening routed WebSocket session from %s to %s with %s by %s", uri.toString(), targetUrl, webSocketClientFactory, this));
try {
WebSocketRoutedSession session = webSocketRoutedSessionFactory.session(webSocketSession, targetUrl, webSocketClientFactory);
routedSessions.put(webSocketSession.getId(), session);

} catch (WebSocketProxyError e) {
log.debug("Error opening WebSocket connection to {}: {}", targetUrl, e.getMessage());
webSocketSession.close(CloseStatus.NOT_ACCEPTABLE.withReason(e.getMessage()));
Expand All @@ -143,8 +158,7 @@ private ServiceInstance findServiceInstance(String serviceId) {
if (!serviceInstances.isEmpty()) {
// TODO: Is this implementation apropriate?
return serviceInstances.get(0);
}
else {
} else {
return null;
}
}
Expand All @@ -161,15 +175,14 @@ public void afterConnectionClosed(WebSocketSession session, CloseStatus status)
}

routedSessions.remove(session.getId());
}
catch (NullPointerException | IOException e) {
} catch (NullPointerException | IOException e) {
log.debug("Error closing WebSocket connection: {}", e.getMessage(), e);
}
}

@Override
public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage)
throws Exception {
throws Exception {
log.debug("handleMessage(session={},message={})", webSocketSession, webSocketMessage);
WebSocketRoutedSession session = getRoutedSession(webSocketSession);
if (session != null) {
Expand Down
2 changes: 2 additions & 0 deletions gateway-service/src/main/resources/application.yml
Expand Up @@ -111,6 +111,8 @@ server:
trustStoreType: PKCS12
maxConnectionsPerRoute: 100
maxTotalConnections: 1000
webSocket:
supportedProtocols: v12.stomp,v11.stomp

zuul:
sslHostnameValidationEnabled: false
Expand Down
Expand Up @@ -14,12 +14,16 @@
import org.junit.jupiter.api.Test;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.socket.*;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.zowe.apiml.product.routing.RoutedService;
import org.zowe.apiml.product.routing.RoutedServices;

import java.net.URI;
import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
Expand All @@ -31,14 +35,12 @@
class WebSocketProxyServerHandlerTest {
private WebSocketProxyServerHandler underTest;
private DiscoveryClient discoveryClient;
private SslContextFactoryProvider sslContextFactoryProvider;
private WebSocketRoutedSessionFactory webSocketRoutedSessionFactory;
private Map<String, WebSocketRoutedSession> routedSessions;

@BeforeEach
public void setup() {
discoveryClient = mock(DiscoveryClient.class);
sslContextFactoryProvider = mock(SslContextFactoryProvider.class);
routedSessions = new HashMap<>();
webSocketRoutedSessionFactory = mock(WebSocketRoutedSessionFactory.class);

Expand All @@ -52,7 +54,7 @@ public void setup() {

/**
* Happy Path
*
* <p>
* The Handler is properly created
* Specified Route is added to the list
* The connection is established
Expand Down Expand Up @@ -92,7 +94,7 @@ private ServiceInstance validServiceInstance() {

/**
* Error Path
*
* <p>
* The Handler is properly created
* The connection is established
* The URI doesn't contain all needed parts
Expand All @@ -111,7 +113,7 @@ void givenInvalidURI_whenTheConnectionIsEstablished_thenTheSocketIsClosedAsNotAc

/**
* Error Path
*
* <p>
* The Handler is properly created
* The connection is established
* The URI contains the service Id for which there is no service
Expand All @@ -130,7 +132,7 @@ void givenInvalidRoute_whenTheConnectionIsEstablished_thenTheSocketIsClosedAsNot

/**
* Error Path
*
* <p>
* The Handler is properly created
* Specified Route is added to the list
* The connection is established
Expand Down

0 comments on commit d1057e0

Please sign in to comment.