diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/net/RespondingServerStanzaHandler.java b/xmppserver/src/main/java/org/jivesoftware/openfire/net/RespondingServerStanzaHandler.java index b8acc171c4..ccd1023f74 100644 --- a/xmppserver/src/main/java/org/jivesoftware/openfire/net/RespondingServerStanzaHandler.java +++ b/xmppserver/src/main/java/org/jivesoftware/openfire/net/RespondingServerStanzaHandler.java @@ -44,6 +44,7 @@ public class RespondingServerStanzaHandler extends StanzaHandler { private static final Logger LOG = LoggerFactory.getLogger(RespondingServerStanzaHandler.class); private final DomainPair domainPair; private boolean isSessionAuthenticated = false; + private boolean attemptedAllAuthenticationMethods; /** * Creates a dedicated reader for a socket. @@ -322,4 +323,16 @@ void createSession(String serverName, XmlPullParser xpp, Connection connection) String currentStreamId = xpp.getAttributeValue("", "id"); session = new LocalOutgoingServerSession(domainPair.getLocal(), connection, BasicStreamIDFactory.createStreamID(currentStreamId)); } + + public void setSessionAuthenticated(boolean authenticated) { + this.isSessionAuthenticated = authenticated; + } + + public boolean haveAttemptedAllAuthenticationMethods() { + return attemptedAllAuthenticationMethods; + } + + public void setAttemptedAllAuthenticationMethods(boolean haveAttemptedAllAuthenticationMethods) { + this.attemptedAllAuthenticationMethods = haveAttemptedAllAuthenticationMethods; + } } diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettyOutboundConnectionHandler.java b/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettyOutboundConnectionHandler.java index fe0e11925b..93614bbccf 100644 --- a/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettyOutboundConnectionHandler.java +++ b/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettyOutboundConnectionHandler.java @@ -17,11 +17,15 @@ package org.jivesoftware.openfire.nio; import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.ssl.SslHandshakeCompletionEvent; +import org.jivesoftware.openfire.Connection; import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.net.RespondingServerStanzaHandler; import org.jivesoftware.openfire.net.StanzaHandler; +import org.jivesoftware.openfire.server.ServerDialback; import org.jivesoftware.openfire.session.ConnectionSettings; import org.jivesoftware.openfire.session.DomainPair; +import org.jivesoftware.openfire.session.LocalOutgoingServerSession; import org.jivesoftware.openfire.spi.ConnectionConfiguration; import org.jivesoftware.util.JiveGlobals; import org.slf4j.Logger; @@ -39,12 +43,21 @@ public class NettyOutboundConnectionHandler extends NettyConnectionHandler { private static final Logger Log = LoggerFactory.getLogger(NettyOutboundConnectionHandler.class); private final DomainPair domainPair; + private final int port; + volatile boolean sslInitDone; - public NettyOutboundConnectionHandler(ConnectionConfiguration configuration, DomainPair domainPair) { + public NettyOutboundConnectionHandler(ConnectionConfiguration configuration, DomainPair domainPair, int port) { super(configuration); this.domainPair = domainPair; + this.port = port; } + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + if (sslInitDone) { + super.channelActive(ctx); + } + } @Override NettyConnection createNettyConnection(ChannelHandlerContext ctx) { return new NettyConnection(ctx, null, configuration); @@ -83,4 +96,44 @@ public void handlerAdded(ChannelHandlerContext ctx) { Log.trace("Adding NettyOutboundConnectionHandler"); super.handlerAdded(ctx); } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (!sslInitDone && evt instanceof SslHandshakeCompletionEvent) { + SslHandshakeCompletionEvent e = (SslHandshakeCompletionEvent) evt; + if (e.isSuccess()) { + sslInitDone = true; + ctx.fireChannelActive(); + } else { + // SSL Handshake has failed, fall back to dialback + RespondingServerStanzaHandler stanzaHandler = (RespondingServerStanzaHandler) ctx.channel().attr(NettyConnectionHandler.HANDLER).get(); + + if (ServerDialback.isEnabled() && connectionConfigDoesNotRequireTls()) { + Log.debug("Unable to create a new session. Going to try connecting using server dialback as a fallback."); + + // Use server dialback (pre XMPP 1.0) over a plain connection + final LocalOutgoingServerSession outgoingSession = new ServerDialback(domainPair).createOutgoingSession(port); + if (outgoingSession != null) { + Log.debug("Successfully created new session (using dialback as a fallback)!"); + stanzaHandler.setSessionAuthenticated(true); + stanzaHandler.setSession(outgoingSession); + } else { + Log.warn("Unable to create a new session: Dialback (as a fallback) failed."); + stanzaHandler.setSession(null); + } + } 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."); + stanzaHandler.setSession(null); + } + + stanzaHandler.setAttemptedAllAuthenticationMethods(true); + } + } + + super.userEventTriggered(ctx, evt); + } + + private boolean connectionConfigDoesNotRequireTls() { + return this.configuration.getTlsPolicy() != Connection.TLSPolicy.required; + } } diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettySessionInitializer.java b/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettySessionInitializer.java index b06b78f3f6..740c4d0782 100644 --- a/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettySessionInitializer.java +++ b/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettySessionInitializer.java @@ -88,7 +88,7 @@ public Future init(ConnectionConfiguration listenerConfiguration) public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new NettyXMPPDecoder()); ch.pipeline().addLast(new StringEncoder()); - ch.pipeline().addLast(new NettyOutboundConnectionHandler(listenerConfiguration, domainPair)); + ch.pipeline().addLast(new NettyOutboundConnectionHandler(listenerConfiguration, domainPair, port)); // Should have a connection if (directTLS) { ch.attr(CONNECTION).get().startTLS(true, true); @@ -140,7 +140,7 @@ private Future waitForSession(Channel channel) { RespondingServerStanzaHandler stanzaHandler = (RespondingServerStanzaHandler) channel.attr(NettyConnectionHandler.HANDLER).get(); return executor.submit(() -> { - while (!stanzaHandler.isSessionAuthenticated()) { + while (!stanzaHandler.isSessionAuthenticated() && !stanzaHandler.haveAttemptedAllAuthenticationMethods()) { Thread.sleep(100); } return stanzaHandler.getSession(); diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/session/LocalOutgoingServerSession.java b/xmppserver/src/main/java/org/jivesoftware/openfire/session/LocalOutgoingServerSession.java index 32c565f460..8647d2fcb2 100644 --- a/xmppserver/src/main/java/org/jivesoftware/openfire/session/LocalOutgoingServerSession.java +++ b/xmppserver/src/main/java/org/jivesoftware/openfire/session/LocalOutgoingServerSession.java @@ -273,22 +273,7 @@ static LocalOutgoingServerSession createOutgoingSession(@Nonnull final DomainPai sessionInitialiser.stop(); } - if (ServerDialback.isEnabled() && configDoesNotRequireTls(listenerConfiguration)) { - log.debug("Unable to create a new session. Going to try connecting using server dialback as a fallback."); - - // Use server dialback (pre XMPP 1.0) over a plain connection - final LocalOutgoingServerSession outgoingSession = new ServerDialback(domainPair).createOutgoingSession(port); - 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)!"); - return outgoingSession; - } else { - log.warn("Unable to create a new session: Dialback (as a fallback) failed."); - return null; - } - } 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."); - return null; - } + return null; }