Skip to content
This repository has been archived by the owner on Sep 18, 2021. It is now read-only.

Commit

Permalink
Added SSL support.
Browse files Browse the repository at this point in the history
  • Loading branch information
garthpatil committed Apr 10, 2013
1 parent fa2e211 commit dfad973
Show file tree
Hide file tree
Showing 18 changed files with 2,475 additions and 6 deletions.
3 changes: 2 additions & 1 deletion .gitignore
@@ -1 +1,2 @@
/target/
*~
target/
4 changes: 3 additions & 1 deletion CHANGELOG.md
Expand Up @@ -3,11 +3,13 @@ Cloudhopper by Twitter

cloudhopper-smpp
----------------
## 5.0.2 - 2013-04-10
- Added SSL support for servers and clients with unit and integration tests.

## 5.0.1 - 2013-03-09
- Added support for cancel_sm and query_sm SMPP messages. Added unit and
integration tests.
- Cleaned up intermittent unit test failures by added delays befrore session
- Cleaned up intermittent unit test failures by added delays before session
close.

## 5.0.0 - 2012-10-26
Expand Down
8 changes: 7 additions & 1 deletion Makefile
Expand Up @@ -5,9 +5,15 @@ client:
performance-client:
mvn -e test-compile exec:java -Dexec.classpathScope="test" -Dexec.mainClass="com.cloudhopper.smpp.demo.PerformanceClientMain"

ssl-client:
mvn -e test-compile exec:java -Dexec.classpathScope="test" -Dexec.mainClass="com.cloudhopper.smpp.demo.SslClientMain"

server:
mvn -e test-compile exec:java -Dexec.classpathScope="test" -Dexec.mainClass="com.cloudhopper.smpp.demo.ServerMain"

ssl-server:
mvn -e test-compile exec:java -Dexec.classpathScope="test" -Dexec.mainClass="com.cloudhopper.smpp.demo.SslServerMain"

slow-server:
mvn -e test-compile exec:java -Dexec.classpathScope="test" -Dexec.mainClass="com.cloudhopper.smpp.demo.SlowServerMain"

Expand All @@ -21,4 +27,4 @@ parser:
mvn -e test-compile exec:java -Dexec.classpathScope="test" -Dexec.mainClass="com.cloudhopper.smpp.demo.ParserMain"

dlr:
mvn -e test-compile exec:java -Dexec.classpathScope="test" -Dexec.mainClass="com.cloudhopper.smpp.demo.DeliveryReceiptMain"
mvn -e test-compile exec:java -Dexec.classpathScope="test" -Dexec.mainClass="com.cloudhopper.smpp.demo.DeliveryReceiptMain"
5 changes: 2 additions & 3 deletions pom.xml
Expand Up @@ -11,8 +11,8 @@
<inceptionYear>2009</inceptionYear>

<scm>
<url>https://github.com/twitter/cloudhopper-smpp</url>
<connection>scm:git:https://github.com/twitter/cloudhopper-smpp.git</connection>
<url>https://github.com/twitter/cloudhopper-smpp</url>
<connection>scm:git:https://github.com/twitter/cloudhopper-smpp.git</connection>
<tag>HEAD</tag>
</scm>

Expand Down Expand Up @@ -44,7 +44,6 @@
<artifactId>netty</artifactId>
<version>${netty.version}</version>
</dependency>

<!-- provided scope -->
<!-- runtime scope -->
<!-- testing scope -->
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/com/cloudhopper/smpp/SmppServerConfiguration.java
Expand Up @@ -20,6 +20,8 @@
* #L%
*/

import com.cloudhopper.smpp.ssl.SslConfiguration;

/**
* Configuration of an SMPP server.
*
Expand All @@ -29,6 +31,9 @@ public class SmppServerConfiguration {

private String name;
private int port;
// SSL
private boolean useSsl = false;
private SslConfiguration sslConfiguration;
// length of time to wait for a bind request
private long bindTimeout;
private String systemId;
Expand Down Expand Up @@ -147,6 +152,23 @@ public void setPort(int port) {
this.port = port;
}

public void setUseSsl(boolean value) {
this.useSsl = value;
}

public boolean isUseSsl() {
return this.useSsl;
}

public void setSslConfiguration(SslConfiguration value) {
this.sslConfiguration = value;
setUseSsl(true);
}

public SslConfiguration getSslConfiguration() {
return this.sslConfiguration;
}

/**
* Set the amount of time to allow a connection to finish binding into the
* server before the server automatically closes the connection.
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/com/cloudhopper/smpp/SmppSessionConfiguration.java
Expand Up @@ -20,6 +20,7 @@
* #L%
*/

import com.cloudhopper.smpp.ssl.SslConfiguration;
import com.cloudhopper.smpp.type.SmppConnectionConfiguration;
import com.cloudhopper.smpp.type.LoggingOptions;
import com.cloudhopper.smpp.type.Address;
Expand All @@ -31,6 +32,9 @@
*/
public class SmppSessionConfiguration extends SmppConnectionConfiguration {

// SSL
private boolean useSsl = false;
private SslConfiguration sslConfiguration;
// other behavioral settings
private String name;
private int windowSize;
Expand Down Expand Up @@ -157,6 +161,25 @@ public long getWindowWaitTimeout() {
return windowWaitTimeout;
}

public void setUseSsl(boolean value) {
// By default, make an SslConfiguration that will trust everything.
if (getSslConfiguration() == null) setSslConfiguration(new SslConfiguration());
this.useSsl = value;
}

public boolean isUseSsl() {
return this.useSsl;
}

public void setSslConfiguration(SslConfiguration value) {
this.sslConfiguration = value;
setUseSsl(true);
}

public SslConfiguration getSslConfiguration() {
return this.sslConfiguration;
}

/**
* Set the amount of time to wait until a slot opens up in the sendWindow.
* Defaults to 60000.
Expand Down
Expand Up @@ -37,5 +37,6 @@ public class SmppChannelConstants {
public static final String PIPELINE_SESSION_LOGGER_NAME = "smppSessionLogger";
public static final String PIPELINE_SESSION_PDU_DECODER_NAME = "smppSessionPduDecoder";
public static final String PIPELINE_SESSION_WRAPPER_NAME = "smppSessionWrapper";
public static final String PIPELINE_SESSION_SSL_NAME = "smppSessionSSL";

}
Expand Up @@ -23,12 +23,16 @@

import com.cloudhopper.smpp.impl.DefaultSmppServer;
import com.cloudhopper.smpp.impl.UnboundSmppSession;
import com.cloudhopper.smpp.ssl.SslConfiguration;
import com.cloudhopper.smpp.ssl.SslContextFactory;
import javax.net.ssl.SSLEngine;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipelineCoverage;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.handler.ssl.SslHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -70,6 +74,16 @@ public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) thr
logger.info("New channel from [{}]", channelName);
Thread.currentThread().setName(currentThreadName);

// add SSL handler
if (server.getConfiguration().isUseSsl()) {
SslConfiguration sslConfig = server.getConfiguration().getSslConfiguration();
if (sslConfig == null) throw new IllegalStateException("sslConfiguration must be set");
SslContextFactory factory = new SslContextFactory(sslConfig);
SSLEngine sslEngine = factory.newSslEngine();
sslEngine.setUseClientMode(false);
channel.getPipeline().addLast(SmppChannelConstants.PIPELINE_SESSION_SSL_NAME, new SslHandler(sslEngine));
}

// add a new instance of a thread renamer
channel.getPipeline().addLast(SmppChannelConstants.PIPELINE_SESSION_THREAD_RENAMER_NAME, new SmppSessionThreadRenamer(threadName));

Expand Down
18 changes: 18 additions & 0 deletions src/main/java/com/cloudhopper/smpp/impl/DefaultSmppClient.java
Expand Up @@ -39,6 +39,8 @@
import com.cloudhopper.smpp.pdu.BindReceiver;
import com.cloudhopper.smpp.pdu.BindTransceiver;
import com.cloudhopper.smpp.pdu.BindTransmitter;
import com.cloudhopper.smpp.ssl.SslConfiguration;
import com.cloudhopper.smpp.ssl.SslContextFactory;
import com.cloudhopper.smpp.type.RecoverablePduException;
import com.cloudhopper.smpp.type.SmppBindException;
import com.cloudhopper.smpp.type.SmppChannelConnectException;
Expand All @@ -47,13 +49,15 @@
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import javax.net.ssl.SSLEngine;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.ClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.ssl.SslHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -217,6 +221,20 @@ protected DefaultSmppSession doOpen(SmppSessionConfiguration config, SmppSession
protected DefaultSmppSession createSession(Channel channel, SmppSessionConfiguration config, SmppSessionHandler sessionHandler) throws SmppTimeoutException, SmppChannelException, InterruptedException {
DefaultSmppSession session = new DefaultSmppSession(SmppSession.Type.CLIENT, config, channel, sessionHandler, monitorExecutor);

// add SSL handler
if (config.isUseSsl()) {
SslConfiguration sslConfig = config.getSslConfiguration();
if (sslConfig == null) throw new IllegalStateException("sslConfiguration must be set");
try {
SslContextFactory factory = new SslContextFactory(sslConfig);
SSLEngine sslEngine = factory.newSslEngine();
sslEngine.setUseClientMode(true);
channel.getPipeline().addLast(SmppChannelConstants.PIPELINE_SESSION_SSL_NAME, new SslHandler(sslEngine));
} catch (Exception e) {
throw new SmppChannelConnectException("Unable to create SSL session]: " + e.getMessage(), e);
}
}

// add the thread renamer portion to the pipeline
if (config.getName() != null) {
channel.getPipeline().addLast(SmppChannelConstants.PIPELINE_SESSION_THREAD_RENAMER_NAME, new SmppSessionThreadRenamer(config.getName()));
Expand Down
@@ -0,0 +1,110 @@
package com.cloudhopper.smpp.ssl;

/*
* #%L
* ch-smpp
* %%
* Copyright (C) 2009 - 2013 Cloudhopper by Twitter
* %%
* Licensed 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.
* #L%
*/

import java.net.Socket;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;

/**
* KeyManager to select a key with desired alias while delegating processing to specified KeyManager.
* Can be used both with server and client sockets.
*/
public class AliasedX509ExtendedKeyManager extends X509ExtendedKeyManager
{
private String keyAlias;
private X509KeyManager keyManager;

/**
* Construct KeyManager instance
* @param keyAlias Alias of the key to be selected
* @param keyManager Instance of KeyManager to be wrapped
* @throws Exception
*/
public AliasedX509ExtendedKeyManager(String keyAlias, X509KeyManager keyManager) throws Exception {
this.keyAlias = keyAlias;
this.keyManager = keyManager;
}

/**
* @see javax.net.ssl.X509KeyManager#chooseClientAlias(java.lang.String[], java.security.Principal[], java.net.Socket)
*/
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
return keyAlias == null ? keyManager.chooseClientAlias(keyType, issuers, socket) : keyAlias;
}

/**
* @see javax.net.ssl.X509KeyManager#chooseServerAlias(java.lang.String, java.security.Principal[], java.net.Socket)
*/
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
return keyAlias == null ? keyManager.chooseServerAlias(keyType, issuers, socket) : keyAlias;
}

/**
* @see javax.net.ssl.X509KeyManager#getClientAliases(java.lang.String, java.security.Principal[])
*/
public String[] getClientAliases(String keyType, Principal[] issuers) {
return keyManager.getClientAliases(keyType, issuers);
}

/**
* @see javax.net.ssl.X509KeyManager#getServerAliases(java.lang.String, java.security.Principal[])
*/
public String[] getServerAliases(String keyType, Principal[] issuers) {
return keyManager.getServerAliases(keyType, issuers);
}

/**
* @see javax.net.ssl.X509KeyManager#getCertificateChain(java.lang.String)
*/
public X509Certificate[] getCertificateChain(String alias) {
return keyManager.getCertificateChain(alias);
}

/**
* @see javax.net.ssl.X509KeyManager#getPrivateKey(java.lang.String)
*/
public PrivateKey getPrivateKey(String alias) {
return keyManager.getPrivateKey(alias);
}

/**
* @see javax.net.ssl.X509ExtendedKeyManager#chooseEngineServerAlias(java.lang.String, java.security.Principal[], javax.net.ssl.SSLEngine)
*/
@Override
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) {
return keyAlias == null ? super.chooseEngineServerAlias(keyType,issuers,engine) : keyAlias;
}

/**
* @see javax.net.ssl.X509ExtendedKeyManager#chooseEngineClientAlias(String[], Principal[], SSLEngine)
*/
@Override
public String chooseEngineClientAlias(String keyType[], Principal[] issuers, SSLEngine engine)
{
return keyAlias == null ? super.chooseEngineClientAlias(keyType,issuers,engine) : keyAlias;
}

}

0 comments on commit dfad973

Please sign in to comment.