You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@synapse.apache.org by hi...@apache.org on 2009/07/31 10:47:29 UTC
svn commit: r799546 - in
/synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp:
HttpCoreNIOSSLSender.java HttpCoreNIOSender.java
SSLClientIOEventDispatch.java
Author: hiranya
Date: Fri Jul 31 08:47:29 2009
New Revision: 799546
URL: http://svn.apache.org/viewvc?rev=799546&view=rev
Log:
Implementing support for multiple SSL configurations at HTTPS transport sender. See SYNAPSE-563 for details. This patch introduces an optional transport sender parameter named "customSSLProfiles". A new IOEventDispatch is provided which supports manipulating multiple SSLContext instances. Still a single IOReactor and a threadpool is used by the sender.
Modified:
synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSSLSender.java
synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSender.java
synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/SSLClientIOEventDispatch.java
Modified: synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSSLSender.java
URL: http://svn.apache.org/viewvc/synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSSLSender.java?rev=799546&r1=799545&r2=799546&view=diff
==============================================================================
--- synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSSLSender.java (original)
+++ synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSSLSender.java Fri Jul 31 08:47:29 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/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSender.java
URL: http://svn.apache.org/viewvc/synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSender.java?rev=799546&r1=799545&r2=799546&view=diff
==============================================================================
--- synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSender.java (original)
+++ synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/HttpCoreNIOSender.java Fri Jul 31 08:47:29 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/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/SSLClientIOEventDispatch.java
URL: http://svn.apache.org/viewvc/synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/SSLClientIOEventDispatch.java?rev=799546&r1=799545&r2=799546&view=diff
==============================================================================
--- synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/SSLClientIOEventDispatch.java (original)
+++ synapse/trunk/java/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/SSLClientIOEventDispatch.java Fri Jul 31 08:47:29 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")));