Skip to content

Commit

Permalink
OF-2559 Faster fallback to Dialback
Browse files Browse the repository at this point in the history
Rather than wait for the Netty-based session to timeout (default 5s) before attempting dialback auth this commit moves the fallback dialback code into Netty-land by listening for `SslHandshakeCompletionEvent`.

There's more refactoring required, I dislike the state leaking through the stanza handler - there is perhaps a need for a connection/session that wraps the netty connection. This concept might already exist but can't quite get my head around it yet.
  • Loading branch information
viv committed Jul 26, 2023
1 parent 3f4b065 commit 20ac715
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public Future<LocalSession> 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);
Expand Down Expand Up @@ -140,7 +140,7 @@ private Future<LocalSession> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}


Expand Down

0 comments on commit 20ac715

Please sign in to comment.