Commit 83165b2e authored by guus's avatar guus

Re-ordered code that initiates outbound S2S connections. Apart from better...

Re-ordered code that initiates outbound S2S connections. Apart from better logging, we're also preferring SASL over Dialback now (OF-452).

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@12239 b35dd754-fafc-0310-a699-88a17e54d16e
parent 904aa2ae
...@@ -405,27 +405,27 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -405,27 +405,27 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
private static LocalOutgoingServerSession secureAndAuthenticate(String hostname, private static LocalOutgoingServerSession secureAndAuthenticate(String hostname,
SocketConnection connection, XMPPPacketReader reader, StringBuilder openingStream, SocketConnection connection, XMPPPacketReader reader, StringBuilder openingStream,
String domain) throws Exception { String domain) throws Exception {
final Logger log = LoggerFactory.getLogger(LocalOutgoingServerSession.class.getName()+"['"+hostname+"']");
Element features; Element features;
Log.debug("LocalOutgoingServerSession: OS - Indicating we want TLS to " + hostname); log.debug("Indicating we want TLS to " + hostname);
connection.deliverRawText("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"); connection.deliverRawText("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
MXParser xpp = reader.getXPPParser(); MXParser xpp = reader.getXPPParser();
// Wait for the <proceed> response // Wait for the <proceed> response
Element proceed = reader.parseDocument().getRootElement(); Element proceed = reader.parseDocument().getRootElement();
if (proceed != null && proceed.getName().equals("proceed")) { if (proceed != null && proceed.getName().equals("proceed")) {
Log.debug("LocalOutgoingServerSession: OS - Negotiating TLS with " + hostname); log.debug("Negotiating TLS...");
boolean needed = JiveGlobals.getBooleanProperty("xmpp.server.certificate.verify", true) && boolean needed = JiveGlobals.getBooleanProperty("xmpp.server.certificate.verify", true) &&
JiveGlobals.getBooleanProperty("xmpp.server.certificate.verify.chain", true) && JiveGlobals.getBooleanProperty("xmpp.server.certificate.verify.chain", true) &&
!JiveGlobals.getBooleanProperty("xmpp.server.certificate.accept-selfsigned", false); !JiveGlobals.getBooleanProperty("xmpp.server.certificate.accept-selfsigned", false);
connection.startTLS(true, hostname, needed ? Connection.ClientAuth.needed : Connection.ClientAuth.wanted); connection.startTLS(true, hostname, needed ? Connection.ClientAuth.needed : Connection.ClientAuth.wanted);
Log.debug("LocalOutgoingServerSession: OS - TLS negotiation with " + hostname + " was successful"); log.debug("TLS negotiation was successful.");
// TLS negotiation was successful so initiate a new stream // TLS negotiation was successful so initiate a new stream
connection.deliverRawText(openingStream.toString()); connection.deliverRawText(openingStream.toString());
// Reset the parser to use the new secured reader // Reset the parser to use the new secured reader
xpp.setInput(new InputStreamReader(connection.getTLSStreamHandler().getInputStream(), xpp.setInput(new InputStreamReader(connection.getTLSStreamHandler().getInputStream(), CHARSET));
CHARSET));
// Skip new stream element // Skip new stream element
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) { for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) {
eventType = xpp.next(); eventType = xpp.next();
...@@ -436,10 +436,8 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -436,10 +436,8 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
features = reader.parseDocument().getRootElement(); features = reader.parseDocument().getRootElement();
if (features != null && (features.element("mechanisms") != null || features.element("dialback") != null)) { if (features != null && (features.element("mechanisms") != null || features.element("dialback") != null)) {
// Check if we can use stream compression // Check if we can use stream compression
String policyName = JiveGlobals.getProperty("xmpp.server.compression.policy", String policyName = JiveGlobals.getProperty("xmpp.server.compression.policy", Connection.CompressionPolicy.disabled.toString());
Connection.CompressionPolicy.disabled.toString()); Connection.CompressionPolicy compressionPolicy = Connection.CompressionPolicy.valueOf(policyName);
Connection.CompressionPolicy compressionPolicy =
Connection.CompressionPolicy.valueOf(policyName);
if (Connection.CompressionPolicy.optional == compressionPolicy) { if (Connection.CompressionPolicy.optional == compressionPolicy) {
// Verify if the remote server supports stream compression // Verify if the remote server supports stream compression
Element compression = features.element("compression"); Element compression = features.element("compression");
...@@ -453,7 +451,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -453,7 +451,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
} }
} }
if (zlibSupported) { if (zlibSupported) {
// Request Stream Compression log.debug("Requesting stream compression (zlib).");
connection.deliverRawText("<compress xmlns='http://jabber.org/protocol/compress'><method>zlib</method></compress>"); connection.deliverRawText("<compress xmlns='http://jabber.org/protocol/compress'><method>zlib</method></compress>");
// Check if we are good to start compression // Check if we are good to start compression
Element answer = reader.parseDocument().getRootElement(); Element answer = reader.parseDocument().getRootElement();
...@@ -461,7 +459,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -461,7 +459,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
// Server confirmed that we can use zlib compression // Server confirmed that we can use zlib compression
connection.addCompression(); connection.addCompression();
connection.startCompression(); connection.startCompression();
Log.debug("LocalOutgoingServerSession: OS - Stream compression was successful with " + hostname); log.debug("Stream compression was successful.");
// Stream compression was successful so initiate a new stream // Stream compression was successful so initiate a new stream
connection.deliverRawText(openingStream.toString()); connection.deliverRawText(openingStream.toString());
// Reset the parser to use stream compression over TLS // Reset the parser to use stream compression over TLS
...@@ -477,75 +475,79 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -477,75 +475,79 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
// Get new stream features // Get new stream features
features = reader.parseDocument().getRootElement(); features = reader.parseDocument().getRootElement();
if (features == null || features.element("mechanisms") == null) { if (features == null || features.element("mechanisms") == null) {
Log.debug("LocalOutgoingServerSession: OS - Error, EXTERNAL SASL was not offered by " + hostname); log.debug("Error, EXTERNAL SASL was not offered.");
return null; return null;
} }
} }
else { else {
Log.debug("LocalOutgoingServerSession: OS - Stream compression was rejected by " + hostname); log.debug("Stream compression was rejected by " + hostname);
} }
} }
else { else {
Log.debug( log.debug("Stream compression found but zlib method is not supported by " + hostname);
"LocalOutgoingServerSession: OS - Stream compression found but zlib method is not supported by" +
hostname);
} }
} }
else { else {
Log.debug("LocalOutgoingServerSession: OS - Stream compression not supoprted by " + hostname); log.debug("Stream compression not supported by " + hostname);
} }
} }
// Skip SASL EXTERNAL and use server dialback over TLS when using self-signed certificates // Bookkeeping: determine what functionality the remote server offers.
boolean dialbackOffered = features.element("dialback") != null; boolean saslEXTERNALoffered = false;
if (!dialbackOffered || !connection.isUsingSelfSignedCertificate()) { if (features.element("mechanisms") != null) {
Iterator it = features.element("mechanisms").elementIterator(); Iterator<Element> it = features.element("mechanisms").elementIterator();
while (it.hasNext()) { while (it.hasNext()) {
Element mechanism = (Element) it.next(); Element mechanism = it.next();
if ("EXTERNAL".equals(mechanism.getTextTrim())) { if ("EXTERNAL".equals(mechanism.getTextTrim())) {
Log.debug("LocalOutgoingServerSession: OS - Starting EXTERNAL SASL with " + hostname); saslEXTERNALoffered = true;
if (doExternalAuthentication(domain, connection, reader)) { break;
Log.debug("LocalOutgoingServerSession: OS - EXTERNAL SASL with " + hostname + " was successful"); }
// SASL was successful so initiate a new stream }
connection.deliverRawText(openingStream.toString()); }
final boolean dialbackOffered = features.element("dialback") != null;
final boolean usesSelfSigned = connection.isUsingSelfSignedCertificate();
// Reset the parser log.debug("Offering dialback functionality: {}",dialbackOffered);
xpp.resetInput(); log.debug("Offering EXTERNAL SASL: {}", saslEXTERNALoffered);
// Skip the opening stream sent by the server log.debug("Is using a self-signed certificate: {}", usesSelfSigned);
for (int eventType = xpp.getEventType();
eventType != XmlPullParser.START_TAG;) { // Skip SASL EXTERNAL and use server dialback over TLS when using self-signed certificates
eventType = xpp.next(); LocalOutgoingServerSession result = null;
if (usesSelfSigned) {
log.debug("As remote server is using self-signed certificate, SASL EXTERNAL is skipped. Attempting dialback over TLS instead.");
result = attemptDialbackOverTLS(connection, reader, domain, hostname, id);
} else {
// first, try SASL
if (saslEXTERNALoffered) {
result = attemptSASLexternal(connection, xpp, reader, domain, hostname, id, openingStream);
}
if (result == null) {
// SASL unavailable or failed, try dialback.
result = attemptDialbackOverTLS(connection, reader, domain, hostname, id);
}
} }
// SASL authentication was successful so create new return result;
// OutgoingServerSession
id = xpp.getAttributeValue("", "id");
StreamID streamID = new BasicStreamIDFactory().createStreamID(id);
LocalOutgoingServerSession session = new LocalOutgoingServerSession(domain,
connection, new OutgoingServerSocketReader(reader), streamID);
connection.init(session);
// Set the hostname as the address of the session
session.setAddress(new JID(null, hostname, null));
// Set that the session was created using TLS+SASL (no server dialback)
session.usingServerDialback = false;
return session;
} }
else { else {
Log.debug("LocalOutgoingServerSession: OS - Error, EXTERNAL SASL authentication with " + hostname + log.debug("Cannot create outgoing server session, as neither SASL mechanisms nor SERVER DIALBACK were offered by " + hostname);
" failed");
return null; return null;
} }
} }
else {
log.debug("Error, <proceed> was not received!");
return null;
} }
} }
// Check if server dialback (over TLS) was offered private static LocalOutgoingServerSession attemptDialbackOverTLS(Connection connection, XMPPPacketReader reader, String domain, String hostname, String id) {
if (dialbackOffered && (ServerDialback.isEnabled() || ServerDialback.isEnabledForSelfSigned())) { final Logger log = LoggerFactory.getLogger(LocalOutgoingServerSession.class.getName()+"['"+hostname+"']");
Log.debug("LocalOutgoingServerSession: OS - About to try connecting using server dialback over TLS with: " + hostname); if (ServerDialback.isEnabled() || ServerDialback.isEnabledForSelfSigned()) {
log.debug("Trying to connecting using dialback over TLS.");
ServerDialback method = new ServerDialback(connection, domain); ServerDialback method = new ServerDialback(connection, domain);
OutgoingServerSocketReader newSocketReader = new OutgoingServerSocketReader(reader); OutgoingServerSocketReader newSocketReader = new OutgoingServerSocketReader(reader);
if (method.authenticateDomain(newSocketReader, domain, hostname, id)) { if (method.authenticateDomain(newSocketReader, domain, hostname, id)) {
Log.debug("LocalOutgoingServerSession: OS - SERVER DIALBACK OVER TLS with " + hostname + " was successful"); log.debug("Dialback over TLS was successful.");
StreamID streamID = new BasicStreamIDFactory().createStreamID(id); StreamID streamID = new BasicStreamIDFactory().createStreamID(id);
LocalOutgoingServerSession session = new LocalOutgoingServerSession(domain, connection, newSocketReader, streamID); LocalOutgoingServerSession session = new LocalOutgoingServerSession(domain, connection, newSocketReader, streamID);
connection.init(session); connection.init(session);
...@@ -554,22 +556,48 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -554,22 +556,48 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
return session; return session;
} }
else { else {
Log.debug("LocalOutgoingServerSession: OS - Error, SERVER DIALBACK with " + hostname + " failed"); log.debug("Dialback over TLS failed");
return null;
} }
} }
else { else {
Log.debug("LocalOutgoingServerSession: OS - Error, EXTERNAL SASL and SERVER DIALBACK were not offered by " + hostname); log.debug("Skipping server dialback attempt as it has been disabled by local configuration.");
return null;
} }
} }
else {
Log.debug("LocalOutgoingServerSession: OS - Error, no SASL mechanisms or SERVER DIALBACK were offered by " + hostname); private static LocalOutgoingServerSession attemptSASLexternal(SocketConnection connection, MXParser xpp, XMPPPacketReader reader, String domain, String hostname, String id, StringBuilder openingStream) throws DocumentException, IOException, XmlPullParserException {
final Logger log = LoggerFactory.getLogger(LocalOutgoingServerSession.class.getName()+"['"+hostname+"']");
log.debug("Starting EXTERNAL SASL.");
if (doExternalAuthentication(domain, connection, reader)) {
log.debug("EXTERNAL SASL was successful.");
// SASL was successful so initiate a new stream
connection.deliverRawText(openingStream.toString());
// Reset the parser
xpp.resetInput();
// Skip the opening stream sent by the server
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) {
eventType = xpp.next();
} }
// SASL authentication was successful so create new OutgoingServerSession
id = xpp.getAttributeValue("", "id");
StreamID streamID = new BasicStreamIDFactory().createStreamID(id);
LocalOutgoingServerSession session = new LocalOutgoingServerSession(domain,
connection, new OutgoingServerSocketReader(reader), streamID);
connection.init(session);
// Set the hostname as the address of the session
session.setAddress(new JID(null, hostname, null));
// Set that the session was created using TLS+SASL (no server dialback)
session.usingServerDialback = false;
return session;
} }
else { else {
Log.debug("LocalOutgoingServerSession: OS - Error, <proceed> was not received"); log.debug("EXTERNAL SASL failed.");
}
return null; return null;
} }
}
private static boolean doExternalAuthentication(String domain, SocketConnection connection, private static boolean doExternalAuthentication(String domain, SocketConnection connection,
XMPPPacketReader reader) throws DocumentException, IOException, XmlPullParserException { XMPPPacketReader reader) throws DocumentException, IOException, XmlPullParserException {
......
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