log.debug("Plain socket connection to {}:{} successful!",hostname,realPort);
break;
}
catch(Exceptione){
Log.warn("Error trying to connect to remote server: "+remoteDomain+
"(DNS lookup: "+hostname+":"+realPort+")",e);
log.debug("An exception occurred while trying to create a plain socket connection to: {}:{}",hostname,realPort,e);
log.warn("Unable to create plain socket connection to: {}:{}. Cause: {} (a full stacktrace is logged on debug level)",hostname,realPort,e.getMessage());
// TODO should this not stop processing? lots of this code is very similar to the implementation in LocalOutgoingServerSession. Should implementations be merged?
log.debug("Unable to validate domain: An incoming connection already exists from this remote host, and multiple connections are not allowed.");
returnfalse;
}
else{
log.debug("Checking to see if the remote host provides stronger authentication based on SASL. If that's the case, dialback-based authentication can be skipped.");
log.debug("Plain socket connection to {}:{} successful!",realHostname,realPort);
break;
}
catch(Exceptione){
Log.warn("Error trying to connect to remote server: "+hostname+
"(DNS lookup: "+realHostname+")",e);
log.debug("An exception occurred while trying to create a plain socket connection to: {}",realHostname,e);
log.warn("Unable to create plain socket connection to: {}. Cause: {} (a full stacktrace is logged on debug level)",realHostname,e.getMessage());
}
}
if(!socket.isConnected()){
log.debug("Unable to validate domain: No server available for verifying key of remote server.");
dialbackError(recipient,hostname,newPacketError(PacketError.Condition.remote_server_not_found,PacketError.Type.cancel,"Unable to connect to authoritative server"));
Log.warn("No server available for verifying key of remote server: "+hostname);
@@ -607,19 +596,24 @@ public class ServerDialback {
connection.deliverRawText(sb.toString());
if(!valid){
// Close the underlying connection
log.debug("Close the underlying connection as key verification failed.");
connection.close();
log.debug("Unable to validate domain: dialback key is invalid.");
returnfalse;
}else{
log.debug("Successfully validated domain!");
returntrue;
}
returnvalid;
default:
break;
}
log.debug("Unable to validate domain: key verification did not complete (the AS likely returned an error or a time out occurred).");
dialbackError(recipient,hostname,newPacketError(PacketError.Condition.remote_server_timeout,PacketError.Type.cancel,"Authoritative server returned error"));
returnfalse;
}
catch(Exceptione){
dialbackError(recipient,hostname,newPacketError(PacketError.Condition.remote_server_timeout,PacketError.Type.cancel,"Authoritative server failed"));
Log.warn("Error verifying key of remote server: "+hostname,e);
log.warn("Unable to validate domain: An exception occurred while verifying the dialback key.",e);
returnfalse;
}
}
...
...
@@ -638,9 +632,12 @@ public class ServerDialback {
log.debug("Got a response. Check if the remote server is XMPP 1.0 compliant...");// TODO there's code duplication here with LocalOutgoingServerSession.
// Do nothing if the target hostname is empty, null or contains whitespaces
log.warn("Unable to authenticate a domain when an empty hostname is provided!");
returnfalse;
}
try{
// Check if the remote hostname is in the blacklist
if(!RemoteServerManager.canAccess(hostname)){
log.info("Unable to authenticate: Hostname is not accessible according to our configuration (typical causes: server federation is disabled, or hostname is blacklisted).");
returnfalse;
}
log.debug("Searching for a pre-existing session to this hostname... If one exists, it will be re-used to authenticate this domain.");
OutgoingServerSessionsession;
// Check if a session, that is using server dialback, already exists to the desired
// hostname (i.e. remote server). If no one exists then create a new session. The same
// session will be used for the same hostname for all the domains to authenticate
// Server is shutting down while we are trying to create a new s2s connection
log.warn("Unable to authenticate: the SessionManager instance is not available. This should not occur unless Openfire is starting up or shutting down.");
log.debug("There is no pre-existing session to this hostname.");
log.debug("Searching for pre-existing sessions to other hostnames that previously authenticated this domain... If one exists, it will be re-used to authenticate this domain.");
// Try locating if the remote server has previously authenticated with this server
Log.warn("Fail to connect to {} for {}",hostname,domain);
log.warn("Unable to authenticate: Fail to create new session.");
returnfalse;
}
}
// A session already exists. The session was established using server dialback so
// it is possible to do piggybacking to authenticate more domains
log.debug("A session already exists. The session was established using server dialback so it is possible to do piggybacking to authenticate more domains.");
log.debug("An exception occurred while trying to create a plain socket connection to: {}:{}",realHostname,realPort,e);
log.warn("Unable to create plain socket connection to: {}:{}. Cause: {} (a full stacktrace is logged on debug level)",realHostname,realPort,e.getMessage());
try{
if(socket!=null){
socket.close();
}
}
catch(IOExceptionex){
Log.debug("Additional exception while trying to close socket when connection to remote server failed: "+ex.toString());
log.debug("Additional exception while trying to close socket when connection to remote server failed.",ex);
}
}
}
if(!socket.isConnected()){
log.info("Unable to create new session: Cannot create a plain socket connection with any applicable host.");
returnnull;
}
...
...
@@ -256,7 +278,7 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou
Log.debug("LocalOutgoingServerSession: OS - Error, SERVER DIALBACK with "+hostname+" failed");
log.debug("Unable to authenticate the connection with dialback.");
}
}
}
else{
Log.debug("LocalOutgoingServerSession: OS - Error, <starttls> was not received");
log.debug("Error! No data from the remote server (expected a 'feature' element).");
}
}else{
log.debug("The remote server is not XMPP 1.0 compliant.");
}
// Something went wrong so close the connection and try server dialback over
// a plain connection
log.debug("Something went wrong so close the connection and try server dialback over a plain connection");
if(connection!=null){
connection.close();
}
...
...
@@ -334,7 +363,7 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou
catch(SSLHandshakeExceptione)
{
// This is a failure as described in RFC3620, section 5.4.3.2 "STARTTLS Failure".
Log.info("STARTTLS negotiation (with {} at {}:{}) failed.",hostname,realHostname,realPort,e);
log.info("STARTTLS negotiation (with {}:{}) failed. Closing connection (without sending any data such as <failure/> or </stream>).",realHostname,realPort,e);
// The receiving entity is expected to close the socket *without* sending any more data (<failure/> nor </stream>).
// It is probably (see OF-794) best if we, as the initiating entity, therefor don't send any data either.
...
...
@@ -345,56 +374,69 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou
catch(Exceptione)
{
// This might be RFC3620, section 5.4.2.2 "Failure Case" or even an unrelated problem. Handle 'normally'.
Log.warn("An exception occurred while creating an encrypted session (with {} at {}:{})",hostname,realHostname,realPort,e);
log.warn("An exception occurred while creating an encrypted session (with {}:{}). Closing connection.",realHostname,realPort,e);
if(connection!=null){
connection.close();
}
}
if(ServerDialback.isEnabled()){
Log.debug("LocalOutgoingServerSession: OS - Going to try connecting using server dialback with: "+hostname);
// Use server dialback (pre XMPP 1.0) over a plain connection
if(outgoingSession!=null){// TODO this success handler behaves differently from a similar success handler above. Shouldn't those be the same?
log.debug("Successfully created new session (using dialback as a fallback)!");
returnoutgoingSession;
}else{
log.warn("Unable to create a new session: Dialback (as a fallback) failed.");
returnnull;
}
}
else
{
log.warn("Unable to create a new session: exhausted all options (not trying dialback as a fallback, as server dialback is disabled by configuration.");