Commit 55d8c08f authored by guus's avatar guus

OF-443: No longer use the dialback namespace definition as a trigger to start...

OF-443: No longer use the dialback namespace definition as a trigger to start dialback (but use the db:verify / db:result elements instead). When the reported version of the stream is absent (prevents compatibility issues with openfire before version 3.7.1) or smaller than one, nothing should be sent on the stream before a db:verify / db:result stanza is sent (no stream features, for example). This mimics old behaviour. This way, dialback appears to be triggered by the namespace definition in the stream (even though in actuality it's triggered by a child element) which makes things backwards compatible.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@12837 b35dd754-fafc-0310-a699-88a17e54d16e
parent 6bed7b67
...@@ -335,6 +335,7 @@ public class ServerDialback { ...@@ -335,6 +335,7 @@ public class ServerDialback {
// Process the answer from the Receiving Server // Process the answer from the Receiving Server
try { try {
while (true) {
Element doc = socketReader.getElement(RemoteServerManager.getSocketTimeout(), Element doc = socketReader.getElement(RemoteServerManager.getSocketTimeout(),
TimeUnit.MILLISECONDS); TimeUnit.MILLISECONDS);
if (doc == null) { if (doc == null) {
...@@ -356,13 +357,13 @@ public class ServerDialback { ...@@ -356,13 +357,13 @@ public class ServerDialback {
return success; return success;
} }
else { else {
Log.debug("ServerDialback: OS - Unexpected answer in validation from: " + hostname + " id: " + Log.warn("ServerDialback: OS - Ignoring unexpected answer in validation from: " + hostname + " id: " +
id + id +
" for domain: " + " for domain: " +
domain + domain +
" answer:" + " answer:" +
doc.asXML()); doc.asXML());
return false; }
} }
} }
catch (InterruptedException e) { catch (InterruptedException e) {
...@@ -398,6 +399,7 @@ public class ServerDialback { ...@@ -398,6 +399,7 @@ public class ServerDialback {
XmlPullParser xpp = reader.getXPPParser(); XmlPullParser xpp = reader.getXPPParser();
StringBuilder sb; StringBuilder sb;
if ("jabber:server:dialback".equals(xpp.getNamespace("db"))) { if ("jabber:server:dialback".equals(xpp.getNamespace("db"))) {
Log.debug("ServerDialback: Processing incoming session.");
StreamID streamID = sessionManager.nextStreamID(); StreamID streamID = sessionManager.nextStreamID();
...@@ -413,9 +415,11 @@ public class ServerDialback { ...@@ -413,9 +415,11 @@ public class ServerDialback {
try { try {
Element doc = reader.parseDocument().getRootElement(); Element doc = reader.parseDocument().getRootElement();
if ("db".equals(doc.getNamespacePrefix()) && "result".equals(doc.getName())) { if ("db".equals(doc.getNamespacePrefix()) && "result".equals(doc.getName())) {
if (validateRemoteDomain(doc, streamID)) {
String hostname = doc.attributeValue("from"); String hostname = doc.attributeValue("from");
String recipient = doc.attributeValue("to"); String recipient = doc.attributeValue("to");
Log.debug("ServerDialback: RS - Validating remote domain for incoming session from {} to {}", hostname, recipient);
if (validateRemoteDomain(doc, streamID)) {
Log.debug("ServerDialback: RS - Validation of remote domain for incoming session from {} to {} was successful.", hostname, recipient);
// Create a server Session for the remote server // Create a server Session for the remote server
LocalIncomingServerSession session = sessionManager. LocalIncomingServerSession session = sessionManager.
createIncomingServerSession(connection, streamID); createIncomingServerSession(connection, streamID);
...@@ -425,6 +429,9 @@ public class ServerDialback { ...@@ -425,6 +429,9 @@ public class ServerDialback {
// validating the session // validating the session
session.setLocalDomain(recipient); session.setLocalDomain(recipient);
return session; return session;
} else {
Log.debug("ServerDialback: RS - Validation of remote domain for incoming session from {} to {} was not successful.", hostname, recipient);
return null;
} }
} }
else if ("db".equals(doc.getNamespacePrefix()) && "verify".equals(doc.getName())) { else if ("db".equals(doc.getNamespacePrefix()) && "verify".equals(doc.getName())) {
...@@ -440,6 +447,7 @@ public class ServerDialback { ...@@ -440,6 +447,7 @@ public class ServerDialback {
return null; return null;
} }
else { else {
Log.debug("ServerDialback: Received an invalid/unknown packet while trying to process an incoming session: {}", doc.asXML());
// The remote server sent an invalid/unknown packet // The remote server sent an invalid/unknown packet
connection.deliverRawText( connection.deliverRawText(
new StreamError(StreamError.Condition.invalid_xml).toXML()); new StreamError(StreamError.Condition.invalid_xml).toXML());
...@@ -457,14 +465,13 @@ public class ServerDialback { ...@@ -457,14 +465,13 @@ public class ServerDialback {
} }
else { else {
// Include the invalid-namespace stream error condition in the response Log.debug("ServerDialback: Received a stanza in an invalid namespace while trying to process an incoming session: {}", xpp.getNamespace("db"));
connection.deliverRawText( connection.deliverRawText(
new StreamError(StreamError.Condition.invalid_namespace).toXML()); new StreamError(StreamError.Condition.invalid_namespace).toXML());
// Close the underlying connection // Close the underlying connection
connection.close(); connection.close();
return null; return null;
} }
return null;
} }
/** /**
...@@ -473,7 +480,7 @@ public class ServerDialback { ...@@ -473,7 +480,7 @@ public class ServerDialback {
* Authoritative Server. The Authoritative Server may be the same Originating Server or * Authoritative Server. The Authoritative Server may be the same Originating Server or
* some other machine in the Originating Server's network.<p> * some other machine in the Originating Server's network.<p>
* *
* If the domain was not valid or some error occured while validating the domain then the * If the domain was not valid or some error occurred while validating the domain then the
* underlying TCP connection will be closed. * underlying TCP connection will be closed.
* *
* @param doc the request for validating the new domain. * @param doc the request for validating the new domain.
......
...@@ -91,14 +91,6 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -91,14 +91,6 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
* before being returned. If the authentication process fails then the answer will be * before being returned. If the authentication process fails then the answer will be
* <tt>null</tt>.<p> * <tt>null</tt>.<p>
* *
* Currently the Server Dialback method is the only way to authenticate a remote server. Since
* Server Dialback requires an Authoritative Server, it is possible for this server to receive
* an incoming connection that will only exist until the requested domain has been validated.
* In this case, this method will return <tt>null</tt> since the connection is closed after
* the domain was validated. See
* {@link org.jivesoftware.openfire.server.ServerDialback#createIncomingSession(org.dom4j.io.XMPPPacketReader)} for more
* information.
*
* @param serverName hostname of this server. * @param serverName hostname of this server.
* @param reader reader on the new established connection with the remote server. * @param reader reader on the new established connection with the remote server.
* @param connection the new established connection with the remote server. * @param connection the new established connection with the remote server.
...@@ -112,52 +104,10 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -112,52 +104,10 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
SocketConnection connection) throws XmlPullParserException, IOException { SocketConnection connection) throws XmlPullParserException, IOException {
XmlPullParser xpp = reader.getXPPParser(); XmlPullParser xpp = reader.getXPPParser();
if (xpp.getNamespace("db") != null) {
if (ServerDialback.isEnabled()) {
Log.debug("Server is trying to establish connection and authenticate using server dialback: " + connection);
ServerDialback method = new ServerDialback(connection, serverName);
return method.createIncomingSession(reader);
} else {
Log.debug("Server is trying to establish connection and authenticate using server dialback, " +
"but Server Dialback is disabled by configuration. Rejecting connection: " + connection);
connection.close();
return null;
}
}
String version = xpp.getAttributeValue("", "version"); String version = xpp.getAttributeValue("", "version");
int[] serverVersion = version != null ? decodeVersion(version) : new int[] {0,0}; int[] serverVersion = version != null ? decodeVersion(version) : new int[] {0,0};
if (serverVersion[0] >= 1) {
// Remote server is XMPP 1.0 compliant so offer TLS and SASL to establish the connection (and server dialback)
try {
return createIncomingSession(connection, serverName);
}
catch (Exception e) {
Log.error("Error establishing connection from remote server:" + connection, e);
connection.close();
return null;
}
}
Log.debug("Server is not 1.0 compliant and is not using dialback to establish and " try {
+ "authenticate the connection. Rejecting connection: "
+ connection);
connection.close();
return null;
}
/**
* Returns a new incoming server session pending to be authenticated. The remote server
* will be notified that TLS and SASL are available. The remote server will be able to
* send packets to this server only after SASL authentication has been finished.
*
* @param connection the new established connection with the remote server.
* @param serverName hostname of this server.
* @return a new incoming server session pending to be authenticated.
* @throws org.jivesoftware.openfire.auth.UnauthorizedException if this server is being shutdown.
*/
private static LocalIncomingServerSession createIncomingSession(SocketConnection connection, String serverName)
throws UnauthorizedException {
// Get the stream ID for the new session // Get the stream ID for the new session
StreamID streamID = SessionManager.getInstance().nextStreamID(); StreamID streamID = SessionManager.getInstance().nextStreamID();
// Create a server Session for the remote server // Create a server Session for the remote server
...@@ -175,6 +125,9 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -175,6 +125,9 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
openingStream.append(" version=\"1.0\">"); openingStream.append(" version=\"1.0\">");
connection.deliverRawText(openingStream.toString()); connection.deliverRawText(openingStream.toString());
if (serverVersion[0] >= 1) {
// Remote server is XMPP 1.0 compliant so offer TLS and SASL to establish the connection (and server dialback)
// Indicate the TLS policy to use for this connection // Indicate the TLS policy to use for this connection
Connection.TLSPolicy tlsPolicy = Connection.TLSPolicy tlsPolicy =
ServerDialback.isEnabled() ? Connection.TLSPolicy.optional : ServerDialback.isEnabled() ? Connection.TLSPolicy.optional :
...@@ -192,6 +145,7 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -192,6 +145,7 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
return null; return null;
} }
connection.setTlsPolicy(hasCertificates ? tlsPolicy : Connection.TLSPolicy.disabled); connection.setTlsPolicy(hasCertificates ? tlsPolicy : Connection.TLSPolicy.disabled);
}
// Indicate the compression policy to use for this connection // Indicate the compression policy to use for this connection
String policyName = JiveGlobals.getProperty("xmpp.server.compression.policy", String policyName = JiveGlobals.getProperty("xmpp.server.compression.policy",
...@@ -201,7 +155,12 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -201,7 +155,12 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
connection.setCompressionPolicy(compressionPolicy); connection.setCompressionPolicy(compressionPolicy);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (serverVersion[0] >= 1) {
// Remote server is XMPP 1.0 compliant so offer TLS and SASL to establish the connection (and server dialback)
// Don't offer stream-features to pre-1.0 servers, as it confuses them. Sending features to Openfire < 3.7.1 confuses it too - OF-443)
sb.append("<stream:features>"); sb.append("<stream:features>");
if (JiveGlobals.getBooleanProperty("xmpp.server.tls.enabled", true)) { if (JiveGlobals.getBooleanProperty("xmpp.server.tls.enabled", true)) {
sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">"); sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">");
if (!ServerDialback.isEnabled()) { if (!ServerDialback.isEnabled()) {
...@@ -210,20 +169,32 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -210,20 +169,32 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
} }
sb.append("</starttls>"); sb.append("</starttls>");
} }
// Include available SASL Mechanisms
sb.append(SASLAuthentication.getSASLMechanisms(session));
if (ServerDialback.isEnabled()) { if (ServerDialback.isEnabled()) {
// Also offer server dialback (when TLS is not required). Server dialback may be offered // Also offer server dialback (when TLS is not required). Server dialback may be offered
// after TLS has been negotiated and a self-signed certificate is being used // after TLS has been negotiated and a self-signed certificate is being used
sb.append("<dialback xmlns=\"urn:xmpp:features:dialback\"/>"); sb.append("<dialback xmlns=\"urn:xmpp:features:dialback\"/>");
} }
// Include available SASL Mechanisms
sb.append(SASLAuthentication.getSASLMechanisms(session));
sb.append("</stream:features>"); sb.append("</stream:features>");
}
connection.deliverRawText(sb.toString()); connection.deliverRawText(sb.toString());
// Set the domain or subdomain of the local server targeted by the remote server // Set the domain or subdomain of the local server targeted by the remote server
session.setLocalDomain(serverName); session.setLocalDomain(serverName);
return session; return session;
} }
catch (Exception e) {
Log.error("Error establishing connection from remote server:" + connection, e);
connection.close();
return null;
}
}
public LocalIncomingServerSession(String serverName, Connection connection, StreamID streamID) { public LocalIncomingServerSession(String serverName, Connection connection, StreamID streamID) {
super(serverName, connection, streamID); super(serverName, connection, streamID);
......
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