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 19, 2018
1 parent b2bbc00 commit d92d208
Show file tree
Hide file tree
Showing 23 changed files with 738 additions and 358 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ public final class Constants {
public static final String LOCALHOST = "localhost";

public static final String HTTP_OBJECT_AGGREGATOR = "HTTP_OBJECT_AGGREGATOR";
public static final String WEBSOCKET_PROTOCOL = "ws";
public static final String WEBSOCKET_PROTOCOL_SECURED = "wss";
public static final String WS_SCHEME = "ws";
public static final String WSS_SCHEME = "wss";
public static final String WEBSOCKET_UPGRADE = "websocket";
public static final String WEBSOCKET_FRAME_HANDLER = "WEBSOCKET_FRAME_HANDLER";
public static final String WEBSOCKET_FRAME_BLOCKING_HANDLER = "WEBSOCKET_FRAME_BLOCKING_HANDLER";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.DefaultHttpResponse;
Expand All @@ -35,15 +36,22 @@
import io.netty.handler.codec.http2.Http2Exception;
import io.netty.handler.codec.http2.Http2Headers;
import io.netty.handler.codec.http2.HttpConversionUtil;
import io.netty.handler.ssl.ReferenceCountedOpenSslContext;
import io.netty.handler.ssl.ReferenceCountedOpenSslEngine;
import io.netty.handler.ssl.SslHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wso2.transport.http.netty.common.ssl.SSLConfig;
import org.wso2.transport.http.netty.common.ssl.SSLHandlerFactory;
import org.wso2.transport.http.netty.config.ChunkConfig;
import org.wso2.transport.http.netty.config.OutboundSslConfiguration;
import org.wso2.transport.http.netty.config.Parameter;
import org.wso2.transport.http.netty.contract.HttpResponseFuture;
import org.wso2.transport.http.netty.message.DefaultListener;
import org.wso2.transport.http.netty.message.HTTPCarbonMessage;
import org.wso2.transport.http.netty.message.Listener;
import org.wso2.transport.http.netty.sender.CertificateValidationHandler;
import org.wso2.transport.http.netty.sender.OCSPStaplingHandler;

import java.io.File;
import java.io.IOException;
Expand All @@ -54,6 +62,8 @@
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;

import static org.wso2.transport.http.netty.common.Constants.COLON;
import static org.wso2.transport.http.netty.common.Constants.HTTP_HOST;
Expand Down Expand Up @@ -341,7 +351,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 Expand Up @@ -374,6 +384,65 @@ public static SSLConfig getSSLConfigForSender(String certPass, String keyStorePa
return sslConfig;
}

/**
* Configure outbound HTTP pipeline for SSL configuration.
*
* @param socketChannel Socket channel of outbound connection
* @param sslConfiguration {@link OutboundSslConfiguration}
* @param host host of the connection
* @param port port of the connection
* @throws SSLException if any error occurs in the SSL connection
*/
public static void configureHttpPipelineForSSL(SocketChannel socketChannel, String host, int port,
OutboundSslConfiguration sslConfiguration) throws SSLException {
log.debug("adding ssl handler");
SSLConfig sslConfig = sslConfiguration.generateSSLConfig();
ChannelPipeline pipeline = socketChannel.pipeline();
if (sslConfiguration.isOcspStaplingEnabled()) {
SSLHandlerFactory sslHandlerFactory = new SSLHandlerFactory(sslConfig);
ReferenceCountedOpenSslContext referenceCountedOpenSslContext = sslHandlerFactory
.buildClientReferenceCountedOpenSslContext();

if (referenceCountedOpenSslContext != null) {
SslHandler sslHandler = referenceCountedOpenSslContext.newHandler(socketChannel.alloc());
ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine();
socketChannel.pipeline().addLast(sslHandler);
socketChannel.pipeline().addLast(new OCSPStaplingHandler(engine));
}
} else {
SSLEngine sslEngine = instantiateAndConfigSSL(sslConfig, host, port,
sslConfiguration.hostNameVerificationEnabled());
pipeline.addLast(Constants.SSL_HANDLER, new SslHandler(sslEngine));
if (sslConfiguration.validateCertEnabled()) {
pipeline.addLast(Constants.HTTP_CERT_VALIDATION_HANDLER,
new CertificateValidationHandler(sslEngine, sslConfiguration.getCacheValidityPeriod(),
sslConfiguration.getCacheSize()));
}
}
}

/**
* Set configurations to create ssl engine.
*
* @param sslConfig ssl related configurations
* @return ssl engine
*/
private static SSLEngine instantiateAndConfigSSL(SSLConfig sslConfig, String host, int port,
boolean hostNameVerificationEnabled) {
// set the pipeline factory, which creates the pipeline for each newly created channels
SSLEngine sslEngine = null;
if (sslConfig != null) {
SSLHandlerFactory sslHandlerFactory = new SSLHandlerFactory(sslConfig);
sslEngine = sslHandlerFactory.buildClientSSLEngine(host, port);
sslEngine.setUseClientMode(true);
sslHandlerFactory.setSNIServerNames(sslEngine, host);
if (hostNameVerificationEnabled) {
sslHandlerFactory.setHostNameVerfication(sslEngine);
}
}
return sslEngine;
}

/**
* Get integer type property value from a property map.
* <p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.wso2.transport.http.netty.config;

import org.wso2.transport.http.netty.common.Util;
import org.wso2.transport.http.netty.common.ssl.SSLConfig;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;

/**
* SSL configuration for Outbound HTTP connection.
*/
public class OutboundSslConfiguration {

@XmlAttribute
private String scheme = "http";

@XmlAttribute
private String keyStoreFile;

@XmlAttribute
private String keyStorePassword;

@XmlAttribute
private String trustStoreFile;

@XmlAttribute
private String trustStorePass;

@XmlAttribute
private String certPass;

@XmlAttribute
private String sslProtocol;

@XmlElementWrapper(name = "parameters")
@XmlElement(name = "parameter")
private List<Parameter> parameters = new ArrayList<>();

private String tlsStoreType;
private boolean hostNameVerificationEnabled = true;
private boolean validateCertEnabled;
private int cacheValidityPeriod = 15;
private int cacheSize = 50;
private boolean ocspStaplingEnabled = false;

public String getCertPass() {
return certPass;
}

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 String getScheme() {
return scheme;
}

public void setScheme(String scheme) {
this.scheme = scheme;
}

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 void setSSLProtocol(String sslProtocol) {
this.sslProtocol = sslProtocol;
}

public String getSSLProtocol() {
return sslProtocol;
}

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

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

public String getTLSStoreType() {
return tlsStoreType;
}

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

public void setValidateCertEnabled(boolean validateCertEnabled) {
this.validateCertEnabled = validateCertEnabled;
}

public boolean validateCertEnabled() {
return validateCertEnabled;
}

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

public boolean hostNameVerificationEnabled() {
return hostNameVerificationEnabled;
}

public void setCacheValidityPeriod(int cacheValidityPeriod) {
this.cacheValidityPeriod = cacheValidityPeriod;
}

public int getCacheValidityPeriod() {
return cacheValidityPeriod;
}

public void setCacheSize(int cacheSize) {
this.cacheSize = cacheSize;
}

public int getCacheSize() {
return cacheSize;
}

public void setOcspStaplingEnabled(boolean ocspStaplingEnabled) {
this.ocspStaplingEnabled = ocspStaplingEnabled;
}

public boolean isOcspStaplingEnabled() {
return ocspStaplingEnabled;
}

public SSLConfig generateSSLConfig() {
if (scheme == null || !scheme.equalsIgnoreCase("https")) {
return null;
}
return Util.getSSLConfigForSender(certPass, keyStorePassword, keyStoreFile, trustStoreFile, trustStorePass,
parameters, sslProtocol, tlsStoreType);
}
}
Loading

0 comments on commit d92d208

Please sign in to comment.