From 155cc0717ccd65c7fd048068e689691729a5fe13 Mon Sep 17 00:00:00 2001 From: Josh Long Date: Tue, 2 Nov 2010 16:34:22 -0700 Subject: [PATCH] INT-1580 this is a beanfactory that knows how to factory an SSL XMPPConnection (as opposed to the regular XmppConnectionFactory) --- .../xmpp/SslXmppConnectionFactory.java | 110 ++++++++++++++++++ .../xmpp/XmppConnectionFactory.java | 44 +++++-- 2 files changed, 146 insertions(+), 8 deletions(-) create mode 100644 spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/SslXmppConnectionFactory.java diff --git a/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/SslXmppConnectionFactory.java b/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/SslXmppConnectionFactory.java new file mode 100644 index 0000000000..3c9095dacf --- /dev/null +++ b/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/SslXmppConnectionFactory.java @@ -0,0 +1,110 @@ +package org.springframework.integration.xmpp; + +import org.jivesoftware.smack.ConnectionConfiguration; + +import org.springframework.core.io.Resource; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLSocketFactory; + + +/** + * An extension of {@link org.springframework.integration.xmpp.XmppConnectionFactory} that handles factorying a secure XMPP connection factory. + *

+ * This is interchangeable with existing {@link org.jivesoftware.smack.XMPPConnection} references, of course. + * + * @author Josh Long + */ +public class SslXmppConnectionFactory extends XmppConnectionFactory { + private volatile String trustStorePassword; + private volatile String trustStoreType; + private volatile Resource trustStore; + private volatile boolean securityEnabled = true ; + private volatile SocketFactory socketFactory; + private volatile ConnectionConfiguration.SecurityMode securityMode = ConnectionConfiguration.SecurityMode.enabled; + + /** + * This method is a callback provided by the super type that lets us plugin to the configuration mechanism + * + * @param connectionConfiguration the connection Configuration + * @throws Exception + */ + + @Override + protected void setupConnectionConfiguration( ConnectionConfiguration connectionConfiguration) throws Exception { + + this.securityEnabled = securityMode != null && + (ConnectionConfiguration.SecurityMode.enabled.equals(securityMode)|| + ConnectionConfiguration.SecurityMode.required.equals(securityMode) ); + + if (this.securityEnabled) { + if (this.socketFactory == null) { + this.socketFactory = SSLSocketFactory.getDefault(); + } + + Assert.notNull(this.trustStore, "'trustStore' must not be null"); + + String trustStorePath = this.trustStore.toString(); + connectionConfiguration.setTruststorePath( trustStorePath); + + // not required + if(StringUtils.hasText( this.trustStorePassword)) + connectionConfiguration.setTruststorePassword(this.trustStorePassword); + + // not required + if(StringUtils.hasText(this.trustStoreType)) + connectionConfiguration.setTruststoreType( this.trustStoreType); + } + } + + /** + * Not required. If not specified, we will load reference using {@link javax.net.ssl.SSLSocketFactory#getDefault()} + * + * @param socketFactory the socket factory to be passed to the {@link org.jivesoftware.smack.ConnectionConfiguration} + * + */ + public void setSocketFactory(SocketFactory socketFactory) { + this.socketFactory = socketFactory; + } + + /** + * the password to use to access the trust store (optional) + * + * @param trustStorePassword + */ + public void setTrustStorePassword(String trustStorePassword) { + this.trustStorePassword = trustStorePassword; + } + + /** + * This is required and specifies the path to the keystore (ie: /path/to/foo.jks) + * + * @param trustStore a {@link org.springframework.core.io.Resource} to the path itself + * + */ + public void setTrustStore(Resource trustStore) { + this.trustStore = trustStore; + } + + /** + * the type of trust store. + * + * @param trustStoreType the type of trust store + */ + public void setTrustStoreType(String trustStoreType) { + this.trustStoreType = trustStoreType; + } + + + /** + * used on {@link org.jivesoftware.smack.ConnectionConfiguration#setSecurityMode(org.jivesoftware.smack.ConnectionConfiguration.SecurityMode)} + * + * basically, if you're using this class we assume you want security enabled. If you don't you can always override it by specifying {@link org.jivesoftware.smack.ConnectionConfiguration.SecurityMode#disabled} + */ + public void setSecurityMode(ConnectionConfiguration.SecurityMode securityMode) { + this.securityMode = securityMode; + } +} diff --git a/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/XmppConnectionFactory.java b/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/XmppConnectionFactory.java index cb2364bbb4..a7592b1127 100644 --- a/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/XmppConnectionFactory.java +++ b/spring-integration-xmpp/src/main/java/org/springframework/integration/xmpp/XmppConnectionFactory.java @@ -149,23 +149,49 @@ public class XmppConnectionFactory extends AbstractFactoryBean { this.subscriptionMode = subscriptionMode; } + @Override public Class getObjectType() { return XMPPConnection.class; } - private XMPPConnection configureAndConnect(String usr, String pw, String host, int port, String serviceName, String resource, String saslMechanismSupported, int saslMechanismSupportedIndex) { + /** + * this provides a hook for subclasses to provide extra setup before the {@link org.jivesoftware.smack.XMPPConnection} is created + * + * @param xmppConnection the connection to configure + * @throws Exception + */ + protected void setupXmppConnectionConfiguration(XMPPConnection xmppConnection) throws Exception { + // noop + } + + /** + * this provides a hook for subclasses to provide extra setup before the {@link org.jivesoftware.smack.ConnectionConfiguration} is created. + * + * @param connectionConfiguration + * @throws Exception + */ + protected void setupConnectionConfiguration(ConnectionConfiguration connectionConfiguration) throws Exception { + // noop + } + + protected XMPPConnection configureAndConnect(String usr, String pw, String host, int port, String serviceName, String resource, String saslMechanismSupported, int saslMechanismSupportedIndex) { if (logger.isDebugEnabled()) { logger.debug(String.format("usr=%s, pw=%s, host=%s, port=%s, serviceName=%s, resource=%s, saslMechanismSupported=%s, saslMechanismSupportedIndex=%s", usr, pw, host, port, serviceName, resource, saslMechanismSupported, saslMechanismSupportedIndex)); } - XMPPConnection.DEBUG_ENABLED = false; // default - - ConnectionConfiguration connectionConfiguration = new ConnectionConfiguration(host, port, serviceName); - XMPPConnection connection = new XMPPConnection(connectionConfiguration); - try { + + XMPPConnection.DEBUG_ENABLED = false; // default + + ConnectionConfiguration connectionConfiguration = new ConnectionConfiguration(host, port, serviceName); + setupConnectionConfiguration(connectionConfiguration); + XMPPConnection connection = new XMPPConnection(connectionConfiguration); + + + setupXmppConnectionConfiguration(connection); + connection.connect(); // You have to put this code before you login @@ -173,6 +199,7 @@ public class XmppConnectionFactory extends AbstractFactoryBean { SASLAuthentication.supportSASLMechanism(saslMechanismSupported, saslMechanismSupportedIndex); } + // You have to specify the resoure (e.g. "@host.com") at the end if (StringUtils.hasText(resource)) { connection.login(usr, pw, resource); @@ -188,11 +215,12 @@ public class XmppConnectionFactory extends AbstractFactoryBean { if (logger.isDebugEnabled()) { logger.debug("authenticated? " + connection.isAuthenticated()); } + + return connection; } catch (Exception e) { logger.warn("failed to establish XMPP connnection", e); } - - return connection; + return null; }