Skip to content

Commit

Permalink
Add SSL support to WebSocket client
Browse files Browse the repository at this point in the history
  • Loading branch information
irunika authored and irunika committed Jun 18, 2018
1 parent 1c12c1b commit ce8f4b1
Show file tree
Hide file tree
Showing 14 changed files with 553 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ public static SSLConfig getSSLConfigForSender(String certPass, String keyStorePa
certPass = keyStorePass;
}
if (trustStoreFilePath == null || trustStorePass == null) {
throw new IllegalArgumentException("TrusStoreFile or trustStorePassword not defined for HTTPS scheme");
throw new IllegalArgumentException("TrustStoreFile or trustStorePassword not defined for HTTPS/WSS scheme");
}
SSLConfig sslConfig = new SSLConfig(null, null).setCertPass(null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@

import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaders;
import org.wso2.transport.http.netty.common.Util;
import org.wso2.transport.http.netty.common.ssl.SSLConfig;
import org.wso2.transport.http.netty.config.Parameter;

import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
Expand All @@ -37,17 +42,22 @@ public class WebSocketClientConnectorConfig {
private boolean autoRead;
private final HttpHeaders headers;

public WebSocketClientConnectorConfig(String remoteAddress) {
this(remoteAddress, null, -1, true);
}
// SSL config
private final String scheme;
private String keyStoreFile;
private String keyStorePassword;
private String trustStoreFile;
private String trustStorePass;
private String certPass;
private String tlsStoreType;
private boolean hostNameVerificationEnabled = true;
private String sslProtocol;
private List<Parameter> parameters = new ArrayList<>();

public WebSocketClientConnectorConfig(String remoteAddress, List<String> subProtocols,
int idleTimeoutInSeconds, boolean autoRead) {
public WebSocketClientConnectorConfig(String remoteAddress) {
this.remoteAddress = remoteAddress;
this.subProtocols = subProtocols;
this.idleTimeoutInSeconds = idleTimeoutInSeconds;
this.autoRead = autoRead;
this.headers = new DefaultHttpHeaders();
this.scheme = URI.create(remoteAddress).getScheme();
}

/**
Expand Down Expand Up @@ -175,4 +185,84 @@ public int getIdleTimeoutInMillis() {
public void setIdleTimeoutInMillis(int idleTimeoutInSeconds) {
this.idleTimeoutInSeconds = idleTimeoutInSeconds;
}

public boolean hostNameVerificationEnabled() {
return hostNameVerificationEnabled;
}

public void setHostNameVerificationEnabled(boolean hostNameVerificationEnabled) {
this.hostNameVerificationEnabled = hostNameVerificationEnabled;
}

public void setSSLProtocol(String sslProtocol) {
this.sslProtocol = sslProtocol;
}

public String getSSLProtocol() {
return sslProtocol;
}

public String getCertPass() {
return certPass;
}

public String getTLSStoreType() {
return tlsStoreType;
}

public void setTLSStoreType(String storeType) {
this.tlsStoreType = storeType;
}

public void setCertPass(String certPass) {
this.certPass = certPass;
}

public String getKeyStoreFile() {
return keyStoreFile;
}

public void setKeyStoreFile(String keyStoreFile) {
this.keyStoreFile = keyStoreFile;
}

public String getKeyStorePassword() {
return keyStorePassword;
}

public void setKeyStorePassword(String keyStorePassword) {
this.keyStorePassword = keyStorePassword;
}

public List<Parameter> getParameters() {
return parameters;
}

public void setParameters(List<Parameter> parameters) {
this.parameters = parameters;
}

public String getTrustStoreFile() {
return trustStoreFile;
}

public void setTrustStoreFile(String trustStoreFile) {
this.trustStoreFile = trustStoreFile;
}

public String getTrustStorePass() {
return trustStorePass;
}

public void setTrustStorePass(String trustStorePass) {
this.trustStorePass = trustStorePass;
}

public SSLConfig getSSLConfig() {
if (scheme == null || !scheme.equalsIgnoreCase("wss")) {
return null;
}
return Util.getSSLConfigForSender(certPass, keyStorePassword, keyStoreFile, trustStoreFile, trustStorePass,
parameters, sslProtocol, tlsStoreType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ public void setClientHandshakeListener(ClientHandshakeListener clientHandshakeLi
this.clientHandshakeListener = clientHandshakeListener;
if (throwable != null) {
clientHandshakeListener.onError(throwable, response);
}
if (webSocketConnection != null && response != null) {
} else if (webSocketConnection != null && response != null) {
clientHandshakeListener.onSuccess(webSocketConnection, response);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
package org.wso2.transport.http.netty.contractimpl.websocket;

import io.netty.channel.EventLoopGroup;
import io.netty.handler.codec.http.HttpHeaders;
import org.wso2.transport.http.netty.contract.websocket.ClientHandshakeFuture;
import org.wso2.transport.http.netty.contract.websocket.WebSocketClientConnector;
import org.wso2.transport.http.netty.contract.websocket.WebSocketClientConnectorConfig;
Expand All @@ -31,27 +30,15 @@
*/
public class DefaultWebSocketClientConnector implements WebSocketClientConnector {

private final String remoteUrl;
private final String subProtocols;
private final int idleTimeout;
private final HttpHeaders customHeaders;
private final EventLoopGroup wsClientEventLoopGroup;
private final boolean autoRead;
private final WebSocketClient webSocketClient;

public DefaultWebSocketClientConnector(WebSocketClientConnectorConfig clientConnectorConfig,
EventLoopGroup wsClientEventLoopGroup) {
this.remoteUrl = clientConnectorConfig.getRemoteAddress();
this.subProtocols = clientConnectorConfig.getSubProtocolsAsCSV();
this.customHeaders = clientConnectorConfig.getHeaders();
this.idleTimeout = clientConnectorConfig.getIdleTimeoutInMillis();
this.wsClientEventLoopGroup = wsClientEventLoopGroup;
this.autoRead = clientConnectorConfig.isAutoRead();
this.webSocketClient = new WebSocketClient(wsClientEventLoopGroup, clientConnectorConfig);
}

@Override
public ClientHandshakeFuture connect() {
WebSocketClient webSocketClient = new WebSocketClient(remoteUrl, subProtocols, idleTimeout,
wsClientEventLoopGroup, customHeaders, autoRead);
return webSocketClient.handshake();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Web

@Override
public void channelInactive(ChannelHandlerContext ctx) throws WebSocketConnectorException {
if (!caughtException && webSocketConnection != null && !this.isCloseFrameReceived() && closePromise == null) {
if (!caughtException && webSocketConnection != null && !closeFrameReceived && closePromise == null) {
// Notify abnormal closure.
DefaultWebSocketMessage webSocketCloseMessage =
new DefaultWebSocketCloseMessage(Constants.WEBSOCKET_STATUS_CODE_ABNORMAL_CLOSURE);
Expand All @@ -140,7 +140,7 @@ public void channelInactive(ChannelHandlerContext ctx) throws WebSocketConnector
return;
}

if (closePromise != null && !closePromise.isDone()) {
if (closePromise != null && !closeFrameReceived) {
String errMsg = "Connection is closed by remote endpoint without echoing a close frame";
ctx.close().addListener(closeFuture -> closePromise.setFailure(new IllegalStateException(errMsg)));
}
Expand Down Expand Up @@ -168,6 +168,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
}
notifyBinaryMessage(binaryFrame, binaryFrame.content(), binaryFrame.isFinalFragment());
} else if (msg instanceof CloseWebSocketFrame) {
closeFrameReceived = true;
notifyCloseMessage((CloseWebSocketFrame) msg);
} else if (msg instanceof PingWebSocketFrame) {
notifyPingMessage((PingWebSocketFrame) msg);
Expand Down Expand Up @@ -221,7 +222,6 @@ private void notifyCloseMessage(CloseWebSocketFrame closeWebSocketFrame) throws
if (closePromise == null) {
DefaultWebSocketMessage webSocketCloseMessage = new DefaultWebSocketCloseMessage(statusCode, reasonText);
setupCommonProperties(webSocketCloseMessage);
closeFrameReceived = true;
connectorFuture.notifyWebSocketListener((WebSocketCloseMessage) webSocketCloseMessage);
} else {
if (webSocketConnection.getCloseInitiatedStatusCode() != closeWebSocketFrame.statusCode()) {
Expand Down
Loading

0 comments on commit ce8f4b1

Please sign in to comment.