Author: hiranya
Date: Fri Jul 31 08:52:46 2009
New Revision: 799548
URL: http://svn.apache.org/viewvc?rev=799548&view=rev
Log:
Implementing support for multiple SSL configurations at HTTPS transport sender.
See SYNAPSE-536 for details.
Modified:
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSSLSender.java
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSender.java
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/SSLClientIOEventDispatch.java
Modified:
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSSLSender.java
URL:
http://svn.apache.org/viewvc/synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSSLSender.java?rev=799548&r1=799547&r2=799548&view=diff
==============================================================================
---
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSSLSender.java
(original)
+++
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSSLSender.java
Fri Jul 31 08:52:46 2009
@@ -33,43 +33,169 @@
import javax.net.ssl.*;
import javax.xml.namespace.QName;
-import java.security.GeneralSecurityException;
+import java.util.Map;
+import java.util.Iterator;
+import java.util.HashMap;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.security.KeyStore;
-import java.net.URL;
+import java.security.GeneralSecurityException;
import java.net.SocketAddress;
import java.net.InetSocketAddress;
-import java.io.IOException;
-import java.io.FileInputStream;
public class HttpCoreNIOSSLSender extends HttpCoreNIOSender{
private static final Log log =
LogFactory.getLog(HttpCoreNIOSSLSender.class);
- protected IOEventDispatch getEventDispatch(
- NHttpClientHandler handler, SSLContext sslContext,
- SSLIOSessionHandler sslIOSessionHandler, HttpParams params) {
- return new SSLClientIOEventDispatch(handler, sslContext,
sslIOSessionHandler, params);
+ protected IOEventDispatch getEventDispatch(NHttpClientHandler handler,
SSLContext sslContext,
+ SSLIOSessionHandler sslIOSessionHandler, HttpParams params,
+ TransportOutDescription transportOut) throws AxisFault {
+
+ SSLClientIOEventDispatch dispatch = new
SSLClientIOEventDispatch(handler, sslContext,
+ sslIOSessionHandler, params);
+ dispatch.setContextMap(getCustomSSLContexts(transportOut));
+ return dispatch;
}
/**
- * Create the SSLContext to be used by this listener
+ * Create the SSLContext to be used by this sender
* @param transportOut the Axis2 transport configuration
* @return the SSLContext to be used
*/
protected SSLContext getSSLContext(TransportOutDescription transportOut)
throws AxisFault {
- KeyManager[] keymanagers = null;
- TrustManager[] trustManagers = null;
-
Parameter keyParam = transportOut.getParameter("keystore");
Parameter trustParam = transportOut.getParameter("truststore");
+ OMElement ksEle = null;
+ OMElement tsEle = null;
+
if (keyParam != null) {
- OMElement ksEle =
keyParam.getParameterElement().getFirstElement();
- String location = ksEle.getFirstChildWithName(new
QName("Location")).getText();
- String type = ksEle.getFirstChildWithName(new
QName("Type")).getText();
- String storePassword = ksEle.getFirstChildWithName(new
QName("Password")).getText();
- String keyPassword = ksEle.getFirstChildWithName(new
QName("KeyPassword")).getText();
+ ksEle = keyParam.getParameterElement().getFirstElement();
+ }
+
+ boolean novalidatecert =
ParamUtils.getOptionalParamBoolean(transportOut,
+ "novalidatecert", false);
+
+ if (trustParam != null) {
+ if (novalidatecert) {
+ log.warn("Ignoring novalidatecert parameter since a truststore
has been specified");
+ }
+ tsEle = trustParam.getParameterElement().getFirstElement();
+ }
+
+ return createSSLContext(ksEle, tsEle, novalidatecert);
+ }
+
+ /**
+ * Create the SSLIOSessionHandler to initialize the host name verification
at the following
+ * levels, through an Axis2 transport configuration parameter as follows:
+ * HostnameVerifier - Default, DefaultAndLocalhost, Strict, AllowAll
+ *
+ * @param transportOut the Axis2 transport configuration
+ * @return the SSLIOSessionHandler to be used
+ * @throws AxisFault if a configuration error occurs
+ */
+ protected SSLIOSessionHandler
getSSLIOSessionHandler(TransportOutDescription transportOut)
+ throws AxisFault {
+
+ final Parameter hostnameVerifier =
transportOut.getParameter("HostnameVerifier");
+ if (hostnameVerifier != null) {
+ return
createSSLIOSessionHandler(hostnameVerifier.getValue().toString());
+ } else {
+ return createSSLIOSessionHandler(null);
+ }
+ }
+
+ /**
+ * Looks for a transport parameter named customSSLProfiles and initializes
zero or more
+ * custom SSLContext instances. The syntax for defining custom SSL
profiles is as follows.
+ *
+ * <parameter name="customSSLProfiles>
+ * <profile>
+ * <servers>www.test.org:80, www.test2.com:9763</servers>
+ * <KeyStore>
+ * <Location>/path/to/identity/store</Location>
+ * <Type>JKS</Type>
+ * <Password>password</Password>
+ * <KeyPassword>password</KeyPassword>
+ * </KeyStore>
+ * <TrustStore>
+ * <Location>path/tp/trust/store</Location>
+ * <Type>JKS</Type>
+ * <Password>password</Password>
+ * </TrustStore>
+ * </profile>
+ * </parameter>
+ *
+ * Any number of profiles can be defined under the customSSLProfiles
parameter.
+ *
+ * @param transportOut transport out description
+ * @return a map of server addresses and SSL contexts
+ * @throws AxisFault if at least on SSL profile is not properly configured
+ */
+ private Map<String, SSLContext>
getCustomSSLContexts(TransportOutDescription transportOut)
+ throws AxisFault {
+
+ if (log.isDebugEnabled()) {
+ log.info("Loading custom SSL profiles for the HTTPS sender");
+ }
+
+ Parameter customProfilesParam =
transportOut.getParameter("customSSLProfiles");
+ if (customProfilesParam == null) {
+ return null;
+ }
+
+ OMElement customProfilesElt =
customProfilesParam.getParameterElement();
+ Iterator profiles = customProfilesElt.getChildrenWithName(new
QName("profile"));
+ Map<String, SSLContext> contextMap = new HashMap<String, SSLContext>();
+ while (profiles.hasNext()) {
+ OMElement profile = (OMElement) profiles.next();
+ OMElement serversElt = profile.getFirstChildWithName(new
QName("servers"));
+ if (serversElt == null || serversElt.getText() == null) {
+ String msg = "Each custom SSL profile must define at least one
host:port " +
+ "pair under the servers element";
+ log.error(msg);
+ throw new AxisFault(msg);
+ }
+
+ String[] servers = serversElt.getText().split(",");
+ OMElement ksElt = profile.getFirstChildWithName(new
QName("KeyStore"));
+ OMElement trElt = profile.getFirstChildWithName(new
QName("TrustStore"));
+ String noValCert = profile.getAttributeValue(new
QName("novalidatecert"));
+ boolean novalidatecert = "true".equals(noValCert);
+ SSLContext sslContext = createSSLContext(ksElt, trElt,
novalidatecert);
+
+ for (String server : servers) {
+ server = server.trim();
+ if (!contextMap.containsKey(server)) {
+ contextMap.put(server, sslContext);
+ } else {
+ log.warn("Multiple SSL profiles were found for the server
: " + server + ". " +
+ "Ignoring the excessive profiles.");
+ }
+ }
+ }
+
+ if (contextMap.size() > 0) {
+ log.info("Custom SSL profiles initialized for " +
contextMap.size() + " servers");
+ return contextMap;
+ }
+ return null;
+ }
+
+ private SSLContext createSSLContext(OMElement keyStoreElt, OMElement
trustStoreElt,
+ boolean novalidatecert) throws
AxisFault {
+
+ KeyManager[] keymanagers = null;
+ TrustManager[] trustManagers = null;
+
+
+ if (keyStoreElt != null) {
+ String location = keyStoreElt.getFirstChildWithName(new
QName("Location")).getText();
+ String type = keyStoreElt.getFirstChildWithName(new
QName("Type")).getText();
+ String storePassword = keyStoreElt.getFirstChildWithName(new
QName("Password")).getText();
+ String keyPassword = keyStoreElt.getFirstChildWithName(new
QName("KeyPassword")).getText();
FileInputStream fis = null;
try {
@@ -98,17 +224,14 @@
}
}
- boolean novalidatecert =
ParamUtils.getOptionalParamBoolean(transportOut, "novalidatecert", false);
-
- if (trustParam != null) {
+ if (trustStoreElt != null) {
if (novalidatecert) {
log.warn("Ignoring novalidatecert parameter since a truststore
has been specified");
}
-
- OMElement tsEle =
trustParam.getParameterElement().getFirstElement();
- String location = tsEle.getFirstChildWithName(new
QName("Location")).getText();
- String type = tsEle.getFirstChildWithName(new
QName("Type")).getText();
- String storePassword = tsEle.getFirstChildWithName(new
QName("Password")).getText();
+
+ String location = trustStoreElt.getFirstChildWithName(new
QName("Location")).getText();
+ String type = trustStoreElt.getFirstChildWithName(new
QName("Type")).getText();
+ String storePassword = trustStoreElt.getFirstChildWithName(new
QName("Password")).getText();
FileInputStream fis = null;
try {
@@ -136,7 +259,8 @@
}
}
} else if (novalidatecert) {
- log.warn("Server certificate validation (trust) has been disabled.
DO NOT USE IN PRODUCTION!");
+ log.warn("Server certificate validation (trust) has been disabled.
" +
+ "DO NOT USE IN PRODUCTION!");
trustManagers = new TrustManager[] { new
NoValidateCertTrustManager() };
}
@@ -144,25 +268,15 @@
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(keymanagers, trustManagers, null);
return sslcontext;
-
+
} catch (GeneralSecurityException gse) {
log.error("Unable to create SSL context with the given
configuration", gse);
throw new AxisFault("Unable to create SSL context with the given
configuration", gse);
}
}
- /**
- * Create the SSLIOSessionHandler to initialize the host name verification
at the following
- * levels, through an Axis2 transport configuration parameter as follows:
- * HostnameVerifier - Default, DefaultAndLocalhost, Strict, AllowAll
- *
- * @param transportOut the Axis2 transport configuration
- * @return the SSLIOSessionHandler to be used
- * @throws AxisFault if a configuration error occurs
- */
- protected SSLIOSessionHandler
getSSLIOSessionHandler(TransportOutDescription transportOut) throws AxisFault {
-
- final Parameter hostnameVerifier =
transportOut.getParameter("HostnameVerifier");
+ private SSLIOSessionHandler createSSLIOSessionHandler(final String
hostnameVerifier)
+ throws AxisFault {
return new SSLIOSessionHandler() {
@@ -172,7 +286,7 @@
public void verify(SocketAddress remoteAddress, SSLSession session)
throws SSLException {
- String address = null;
+ String address;
if (remoteAddress instanceof InetSocketAddress) {
address = ((InetSocketAddress)
remoteAddress).getHostName();
} else {
@@ -181,11 +295,11 @@
boolean valid = false;
if (hostnameVerifier != null) {
- if ("Strict".equals(hostnameVerifier.getValue())) {
+ if ("Strict".equals(hostnameVerifier)) {
valid = HostnameVerifier.STRICT.verify(address,
session);
- } else if ("AllowAll".equals(hostnameVerifier.getValue()))
{
+ } else if ("AllowAll".equals(hostnameVerifier)) {
valid = HostnameVerifier.ALLOW_ALL.verify(address,
session);
- } else if
("DefaultAndLocalhost".equals(hostnameVerifier.getValue())) {
+ } else if ("DefaultAndLocalhost".equals(hostnameVerifier))
{
valid =
HostnameVerifier.DEFAULT_AND_LOCALHOST.verify(address, session);
}
} else {
@@ -193,7 +307,7 @@
}
if (!valid) {
- throw new SSLException("Host name verification failed for
host : " + address);
+ throw new SSLException("Host name verification failed for
host : " + address);
}
}
};
Modified:
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSender.java
URL:
http://svn.apache.org/viewvc/synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSender.java?rev=799548&r1=799547&r2=799548&view=diff
==============================================================================
---
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSender.java
(original)
+++
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSender.java
Fri Jul 31 08:52:46 2009
@@ -175,7 +175,7 @@
handler = new ClientHandler(cfgCtx, params, metrics);
final IOEventDispatch ioEventDispatch = getEventDispatch(
- handler, sslContext, sslIOSessionHandler, params);
+ handler, sslContext, sslIOSessionHandler, params, transportOut);
// start the Sender in a new seperate thread
Thread t = new Thread(new Runnable() {
@@ -209,9 +209,10 @@
* @param params
* @return
*/
- protected IOEventDispatch getEventDispatch(
- NHttpClientHandler handler, SSLContext sslContext,
- SSLIOSessionHandler sslIOSessionHandler, HttpParams params) {
+ protected IOEventDispatch getEventDispatch(NHttpClientHandler handler,
SSLContext sslContext,
+ SSLIOSessionHandler sslIOSessionHandler, HttpParams params,
+ TransportOutDescription trpOut) throws AxisFault {
+
return new PlainClientIOEventDispatch(handler, params);
}
Modified:
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/SSLClientIOEventDispatch.java
URL:
http://svn.apache.org/viewvc/synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/SSLClientIOEventDispatch.java?rev=799548&r1=799547&r2=799548&view=diff
==============================================================================
---
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/SSLClientIOEventDispatch.java
(original)
+++
synapse/branches/1.3/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/SSLClientIOEventDispatch.java
Fri Jul 31 08:52:46 2009
@@ -21,14 +21,25 @@
import javax.net.ssl.SSLContext;
import org.apache.http.impl.nio.reactor.SSLIOSessionHandler;
+import org.apache.http.impl.nio.reactor.SSLIOSession;
import org.apache.http.nio.NHttpClientHandler;
import org.apache.http.nio.NHttpClientIOTarget;
import org.apache.http.nio.reactor.IOSession;
import org.apache.http.params.HttpParams;
+import java.net.InetSocketAddress;
+import java.util.Map;
+
+/**
+ * This custom SSLClientIOEventDispatch can keep a map of SSLContexts and use
the correct
+ * SSLContext when connecting to different servers. If a SSLContext cannot be
found for a
+ * particular server from the specified map it uses the default SSLContext.
+ */
public class SSLClientIOEventDispatch
extends org.apache.http.impl.nio.SSLClientIOEventDispatch {
+ private Map<String, SSLContext> contextMap;
+
public SSLClientIOEventDispatch(
final NHttpClientHandler handler,
final SSLContext sslcontext,
@@ -36,15 +47,29 @@
final HttpParams params) {
super(LoggingUtils.decorate(handler), sslcontext, sslHandler, params);
}
-
- public SSLClientIOEventDispatch(
- final NHttpClientHandler handler,
- final SSLContext sslcontext,
- final HttpParams params) {
- this(handler, sslcontext, null, params);
+
+ public void setContextMap(Map<String,SSLContext> contextMap) {
+ this.contextMap = contextMap;
+ }
+
+ protected SSLIOSession createSSLIOSession(IOSession ioSession, SSLContext
sslContext,
+ SSLIOSessionHandler
sslioSessionHandler) {
+
+ InetSocketAddress address = (InetSocketAddress)
ioSession.getRemoteAddress();
+ String host = address.getHostName() + ":" + address.getPort();
+ SSLContext customContext = null;
+ if (contextMap != null) {
+ // See if there's a custom SSL profile configured for this server
+ customContext = contextMap.get(host);
+ }
+
+ if (customContext == null) {
+ customContext = sslContext;
+ }
+
+ return super.createSSLIOSession(ioSession, customContext,
sslioSessionHandler);
}
-
- @Override
+
protected NHttpClientIOTarget createConnection(IOSession session) {
return LoggingUtils.decorate(
super.createConnection(LoggingUtils.decorate(session,
"sslclient")));