From c3ddc1ada91a027b028943a9c077339d60426ab0 Mon Sep 17 00:00:00 2001 From: Guus der Kinderen Date: Wed, 11 May 2016 13:12:52 +0200 Subject: [PATCH] WHACK-21: Add encryption option This commit adds an option to have the connection between the XMPP server and the external component be encrypted. Note that this does not employ STARTTLS, but 'natively' born encrypted sockets. --- .../weather/ExternalWeatherComponent.java | 2 +- .../weather/ExternalWeatherComponent.java | 12 ++++++-- .../jivesoftware/whack/ExternalComponent.java | 28 +++++++++++++++++-- .../whack/ExternalComponentManager.java | 23 ++++++++++++++- .../whack/container/ServerContainer.java | 2 +- 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/sample/weather/source/java/org/jivesoftware/weather/ExternalWeatherComponent.java b/sample/weather/source/java/org/jivesoftware/weather/ExternalWeatherComponent.java index c153cd2..ad66d9c 100644 --- a/sample/weather/source/java/org/jivesoftware/weather/ExternalWeatherComponent.java +++ b/sample/weather/source/java/org/jivesoftware/weather/ExternalWeatherComponent.java @@ -15,7 +15,7 @@ public class ExternalWeatherComponent { public static void main(String[] args) { // Create a manager for the external components that will connect to the server "localhost" // at the port 5225 - final ExternalComponentManager manager = new ExternalComponentManager("localhost", 5275); + final ExternalComponentManager manager = new ExternalComponentManager("localhost", 5275, false); // Set the secret key for this component. The server must be using the same secret key // otherwise the component won't be able to authenticate with the server. Check that the // server has the property "component.external.secretKey" defined and that it is using the diff --git a/sample/weatherabstract/source/java/org/jivesoftware/weather/ExternalWeatherComponent.java b/sample/weatherabstract/source/java/org/jivesoftware/weather/ExternalWeatherComponent.java index cac40f2..b215328 100644 --- a/sample/weatherabstract/source/java/org/jivesoftware/weather/ExternalWeatherComponent.java +++ b/sample/weatherabstract/source/java/org/jivesoftware/weather/ExternalWeatherComponent.java @@ -3,6 +3,14 @@ import org.jivesoftware.whack.ExternalComponentManager; import org.xmpp.component.ComponentException; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + /** * This is an example of how to make a component run as an external component. This examples * requires that the server be running in the same computer where this application will run and @@ -14,8 +22,8 @@ public class ExternalWeatherComponent { public static void main(String[] args) { // Create a manager for the external components that will connect to the server "localhost" - // at the port 5225 - final ExternalComponentManager manager = new ExternalComponentManager("localhost", 5275); + // at the port 5276, using encryption. + final ExternalComponentManager manager = new ExternalComponentManager("localhost", 5276, true); // Set the secret key for this component. The server must be using the same secret key // otherwise the component won't be able to authenticate with the server. Check that the // server has the property "component.external.secretKey" defined and that it is using the diff --git a/source/java/org/jivesoftware/whack/ExternalComponent.java b/source/java/org/jivesoftware/whack/ExternalComponent.java index 608618b..e7641ab 100644 --- a/source/java/org/jivesoftware/whack/ExternalComponent.java +++ b/source/java/org/jivesoftware/whack/ExternalComponent.java @@ -54,6 +54,8 @@ import org.xmpp.packet.Packet; import org.xmpp.packet.StreamError; +import javax.net.ssl.SSLSocketFactory; + /** * ExternalComponents are responsible for connecting and authenticating with a remote server and * for sending and processing received packets. In fact, an ExternalComponent is a wrapper on a @@ -107,6 +109,8 @@ public class ExternalComponent implements Component { private String host; private int port; + private boolean startEncrypted; + /** * Pool of threads that are available for processing the requests. */ @@ -144,10 +148,29 @@ public ExternalComponent(Component component, ExternalComponentManager manager, * @param subdomain the subdomain that this component will be handling. * @throws ComponentException if an error happens during the connection and authentication steps. */ + @Deprecated public void connect(String host, int port, String subdomain) throws ComponentException { + connect(host,port,subdomain,false); + } + + /** + * Generates a connection with the server and tries to authenticate. If an error occurs in any + * of the steps then a ComponentException is thrown. + * + * @param host the host to connect with. + * @param port the port to use. + * @param subdomain the subdomain that this component will be handling. + * @param startEncrypted true if sockets are started in TLS/SSL mode, otherwise false. + * @throws ComponentException if an error happens during the connection and authentication steps. + */ + public void connect(String host, int port, String subdomain, boolean startEncrypted) throws ComponentException { try { // Open a socket to the server - this.socket = new Socket(); + if ( startEncrypted ) { + this.socket = SSLSocketFactory.getDefault().createSocket(); + } else { + this.socket = new Socket(); + } socket.connect(new InetSocketAddress(host, port), manager.getConnectTimeout()); if (manager.getServerName() != null) { this.domain = subdomain + "." + manager.getServerName(); @@ -159,6 +182,7 @@ public void connect(String host, int port, String subdomain) throws ComponentExc // Keep these variables that will be used in case a reconnection is required this.host= host; this.port = port; + this.startEncrypted = startEncrypted; try { factory = XmlPullParserFactory.newInstance(); @@ -432,7 +456,7 @@ public void connectionLost() { } while (!isConnected && !shutdown) { try { - connect(host, port, subdomain); + connect(host, port, subdomain, startEncrypted); isConnected = true; // It may be possible that while a new connection was being established the // component was required to shutdown so in this case we need to close the new diff --git a/source/java/org/jivesoftware/whack/ExternalComponentManager.java b/source/java/org/jivesoftware/whack/ExternalComponentManager.java index 403db3f..3d18f4e 100644 --- a/source/java/org/jivesoftware/whack/ExternalComponentManager.java +++ b/source/java/org/jivesoftware/whack/ExternalComponentManager.java @@ -57,6 +57,12 @@ public class ExternalComponentManager implements ComponentManager { * Port of the server used for establishing new connections. */ private int port; + + /** + * Defines if sockets are started in encrypted mode ("old-style" TLS/SSL, non-STARTTLS + */ + private boolean startEncrypted; + /** * Keeps the domain of the XMPP server. The domain may or may not match the host. The domain * will be used mainly for the XMPP packets while the host is used mainly for creating @@ -117,6 +123,7 @@ public ExternalComponentManager(String host) { * @param host the IP address or name of the XMPP server to connect to (e.g. "example.com"). * @param port the port to connect on. */ + @Deprecated public ExternalComponentManager(String host, int port) { if (host == null) { throw new IllegalArgumentException("Host of XMPP server cannot be null"); @@ -130,6 +137,20 @@ public ExternalComponentManager(String host, int port) { ComponentManagerFactory.setComponentManager(this); } + public ExternalComponentManager(String host, int port, boolean startEncrypted) { + if (host == null) { + throw new IllegalArgumentException("Host of XMPP server cannot be null"); + } + this.host = host; + this.port = port; + this.startEncrypted = startEncrypted; + + createDummyLogger(); + + // Set this ComponentManager as the current component manager + ComponentManagerFactory.setComponentManager(this); + } + /** * Sets a secret key for a sub-domain, for future use by a component * connecting to the server. Keys are used as an authentication mechanism @@ -218,7 +239,7 @@ public void addComponent(String subdomain, Component component, Integer port) th componentsByDomain.put(subdomain, externalComponent); components.put(component, externalComponent); // Ask the ExternalComponent to connect with the remote server - externalComponent.connect(host, port, subdomain); + externalComponent.connect(host, port, subdomain, startEncrypted); // Initialize the component JID componentJID = new JID(null, externalComponent.getDomain(), null); externalComponent.initialize(componentJID, this); diff --git a/source/java/org/jivesoftware/whack/container/ServerContainer.java b/source/java/org/jivesoftware/whack/container/ServerContainer.java index 280e87c..74ba69e 100644 --- a/source/java/org/jivesoftware/whack/container/ServerContainer.java +++ b/source/java/org/jivesoftware/whack/container/ServerContainer.java @@ -179,7 +179,7 @@ public void start() { String xmppServerHost = properties.getProperty("xmppServer.host"); port = properties.getProperty("xmppServer.port"); int xmppServerPort = (port == null ? 10015 : Integer.parseInt(port)); - manager = new ExternalComponentManager(xmppServerHost, xmppServerPort); + manager = new ExternalComponentManager(xmppServerHost, xmppServerPort, false); String serverDomain = properties.getProperty("xmppServer.domain"); if (serverDomain != null) { manager.setServerName(serverDomain);