Commit 17fbe3a9 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

TLS and SSL can now be disabled, enabled (optional, required). JM-393

git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@3087 b35dd754-fafc-0310-a699-88a17e54d16e
parent b9a0ba1e
......@@ -55,6 +55,8 @@ public class ClientSession extends Session {
*/
private static Map<String,String> allowedIPs = new HashMap<String,String>();
private static SocketConnection.TLSPolicy tlsPolicy;
/**
* The authentication token for this session.
*/
......@@ -86,6 +88,11 @@ public class ClientSession extends Session {
String address = tokens.nextToken().trim();
allowedIPs.put(address, "");
}
// Set the TLS policy stored as a system property
String policyName = JiveGlobals.getProperty("xmpp.client.tls.policy",
SocketConnection.TLSPolicy.optional.toString());
tlsPolicy = SocketConnection.TLSPolicy.valueOf(policyName);
}
/**
......@@ -191,6 +198,9 @@ public class ClientSession extends Session {
connection.setLanaguage(language);
connection.setXMPPVersion(majorVersion, minorVersion);
// Indicate the TLS policy to use for this connection
connection.setTlsPolicy(tlsPolicy);
// Create a ClientSession for this user.
Session session = SessionManager.getInstance().createClientSession(connection);
......@@ -235,10 +245,13 @@ public class ClientSession extends Session {
sb = new StringBuilder();
sb.append("<stream:features>");
sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">");
// TODO Consider that STARTTLS may be optional (add TLS options to the AC - disabled, optional, required)
// sb.append("<required/>");
sb.append("</starttls>");
if (tlsPolicy != SocketConnection.TLSPolicy.disabled) {
sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">");
if (tlsPolicy == SocketConnection.TLSPolicy.required) {
sb.append("<required/>");
}
sb.append("</starttls>");
}
// Include available SASL Mechanisms
sb.append(SASLAuthentication.getSASLMechanisms(session));
sb.append("</stream:features>");
......@@ -288,6 +301,33 @@ public class ClientSession extends Session {
}
}
/**
* Returns whether TLS is mandatory, optional or is disabled for clients. When TLS is
* mandatory clients are required to secure their connections or otherwise their connections
* will be closed. On the other hand, when TLS is disabled clients are not allowed to secure
* their connections using TLS. Their connections will be closed if they try to secure the
* connection. in this last case.
*
* @return whether TLS is mandatory, optional or is disabled.
*/
public static SocketConnection.TLSPolicy getTLSPolicy() {
return tlsPolicy;
}
/**
* Sets whether TLS is mandatory, optional or is disabled for clients. When TLS is
* mandatory clients are required to secure their connections or otherwise their connections
* will be closed. On the other hand, when TLS is disabled clients are not allowed to secure
* their connections using TLS. Their connections will be closed if they try to secure the
* connection. in this last case.
*
* @param policy whether TLS is mandatory, optional or is disabled.
*/
public static void setTLSPolicy(SocketConnection.TLSPolicy policy) {
tlsPolicy = policy;
JiveGlobals.setProperty("xmpp.client.tls.policy", tlsPolicy.toString());
}
/**
* Creates a session with an underlying connection and permission protection.
*
......
......@@ -58,6 +58,10 @@ public class SocketConnection implements Connection {
private int minorVersion = 0;
private String language = null;
private TLSStreamHandler tlsStreamHandler;
/**
* TLS policy currently in use for this connection.
*/
private TLSPolicy tlsPolicy = TLSPolicy.optional;
/**
* Create a new session using the supplied socket.
......@@ -168,6 +172,32 @@ public class SocketConnection implements Connection {
return secure;
}
/**
* Returns whether TLS is mandatory, optional or is disabled. When TLS is mandatory clients
* are required to secure their connections or otherwise their connections will be closed.
* On the other hand, when TLS is disabled clients are not allowed to secure their connections
* using TLS. Their connections will be closed if they try to secure the connection. in this
* last case.
*
* @return whether TLS is mandatory, optional or is disabled.
*/
public TLSPolicy getTlsPolicy() {
return tlsPolicy;
}
/**
* Sets whether TLS is mandatory, optional or is disabled. When TLS is mandatory clients
* are required to secure their connections or otherwise their connections will be closed.
* On the other hand, when TLS is disabled clients are not allowed to secure their connections
* using TLS. Their connections will be closed if they try to secure the connection. in this
* last case.
*
* @param tlsPolicy whether TLS is mandatory, optional or is disabled.
*/
public void setTlsPolicy(TLSPolicy tlsPolicy) {
this.tlsPolicy = tlsPolicy;
}
public int getMajorXMPPVersion() {
return majorVersion;
}
......@@ -375,4 +405,28 @@ public class SocketConnection implements Connection {
public String toString() {
return super.toString() + " socket: " + socket + " session: " + session;
}
/**
* Enumeration of possible TLS policies required to interact with the server.
*/
public enum TLSPolicy {
/**
* TLS is required to interact with the server. Entities that do not secure their
* connections using TLS will get a stream error and their connections will be closed.
*/
required,
/**
* TLS is optional to interact with the server. Entities may or may not secure their
* connections using TLS.
*/
optional,
/**
* TLS is not available. Entities that request a TLS negotiation will get a stream
* error and their connections will be closed.
*/
disabled;
}
}
\ No newline at end of file
......@@ -12,6 +12,7 @@
package org.jivesoftware.messenger.net;
import org.dom4j.Element;
import org.dom4j.DocumentException;
import org.dom4j.io.XPPPacketReader;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
......@@ -29,7 +30,6 @@ import org.xmpp.packet.*;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.net.Socket;
import java.net.SocketException;
import java.nio.channels.AsynchronousCloseException;
......@@ -249,8 +249,6 @@ public abstract class SocketReader implements Runnable {
processIQ(packet);
}
else if ("starttls".equals(tag)) {
// Client requested to secure the connection using TLS
connection.deliverRawText("<proceed xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
// Negotiate TLS
if (negotiateTLS()) {
tlsNegotiated();
......@@ -263,8 +261,7 @@ public abstract class SocketReader implements Runnable {
}
else if ("auth".equals(tag)) {
// User is trying to authenticate using SASL
SASLAuthentication saslAuth = new SASLAuthentication(session, reader);
if (saslAuth.doHandshake(doc)) {
if (authenticateClient(doc)) {
// SASL authentication was successful so open a new stream and offer
// resource binding and session establishment (to client sessions only)
saslSuccessful();
......@@ -285,6 +282,18 @@ public abstract class SocketReader implements Runnable {
}
}
private boolean authenticateClient(Element doc) throws DocumentException, IOException,
XmlPullParserException {
// Ensure that connection was secured if TLS was required
if (connection.getTlsPolicy() == SocketConnection.TLSPolicy.required &&
!connection.isSecure()) {
closeNeverSecuredConnection();
return false;
}
SASLAuthentication saslAuth = new SASLAuthentication(session, reader);
return saslAuth.doHandshake(doc);
}
/**
* Process the received IQ packet. Registered
* {@link org.jivesoftware.messenger.interceptor.PacketInterceptor} will be invoked before
......@@ -297,6 +306,12 @@ public abstract class SocketReader implements Runnable {
* @param packet the received packet.
*/
protected void processIQ(IQ packet) throws UnauthorizedException {
// Ensure that connection was secured if TLS was required
if (connection.getTlsPolicy() == SocketConnection.TLSPolicy.required &&
!connection.isSecure()) {
closeNeverSecuredConnection();
return;
}
try {
// Invoke the interceptors before we process the read packet
InterceptorManager.getInstance().invokeInterceptors(packet, session, true,
......@@ -340,6 +355,12 @@ public abstract class SocketReader implements Runnable {
* @param packet the received packet.
*/
protected void processPresence(Presence packet) throws UnauthorizedException {
// Ensure that connection was secured if TLS was required
if (connection.getTlsPolicy() == SocketConnection.TLSPolicy.required &&
!connection.isSecure()) {
closeNeverSecuredConnection();
return;
}
try {
// Invoke the interceptors before we process the read packet
InterceptorManager.getInstance().invokeInterceptors(packet, session, true,
......@@ -382,6 +403,12 @@ public abstract class SocketReader implements Runnable {
* @param packet the received packet.
*/
protected void processMessage(Message packet) throws UnauthorizedException {
// Ensure that connection was secured if TLS was required
if (connection.getTlsPolicy() == SocketConnection.TLSPolicy.required &&
!connection.isSecure()) {
closeNeverSecuredConnection();
return;
}
try {
// Invoke the interceptors before we process the read packet
InterceptorManager.getInstance().invokeInterceptors(packet, session, true,
......@@ -418,6 +445,24 @@ public abstract class SocketReader implements Runnable {
*/
abstract boolean processUnknowPacket(Element doc);
/**
* Close the connection since TLS was mandatory and the entity never negotiated TLS. Before
* closing the connection a stream error will be sent to the entity.
*/
private void closeNeverSecuredConnection() {
StringBuilder sb = new StringBuilder();
// Set the not_authorized error
StreamError error = new StreamError(StreamError.Condition.not_authorized);
sb.append(error.toXML());
// Deliver stanza
connection.deliverRawText(sb.toString());
// Close the underlying connection
connection.close();
// Log a warning so that admins can track this case from the server side
Log.warn("TLS was required by the server and connection was never secured. " +
"Closing connection : " + connection);
}
private IQ getIQ(Element doc) {
Element query = doc.element("query");
if (query != null && "jabber:iq:roster".equals(query.getNamespaceURI())) {
......@@ -536,6 +581,22 @@ public abstract class SocketReader implements Runnable {
* @throws XmlPullParserException if an error occures while parsing.
*/
private boolean negotiateTLS() throws IOException, XmlPullParserException {
if (connection.getTlsPolicy() == SocketConnection.TLSPolicy.disabled) {
StringBuilder sb = new StringBuilder();
// Set the not_authorized error
StreamError error = new StreamError(StreamError.Condition.not_authorized);
sb.append(error.toXML());
// Deliver stanza
connection.deliverRawText(sb.toString());
// Close the underlying connection
connection.close();
// Log a warning so that admins can track this case from the server side
Log.warn("TLS requested by initiator when TLS was never offered by server. " +
"Closing connection : " + connection);
return false;
}
// Client requested to secure the connection using TLS
connection.deliverRawText("<proceed xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
// Negotiate TLS.
try {
connection.startTLS(false);
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment