explicitly search for namespaces when processing stream features

This commit is contained in:
Daniel Gultsch 2022-08-29 15:09:53 +02:00
parent b792563fad
commit a717917b3d
3 changed files with 42 additions and 12 deletions

View file

@ -66,4 +66,8 @@ public abstract class SaslMechanism {
public String getResponse(final String challenge) throws AuthenticationException { public String getResponse(final String challenge) throws AuthenticationException {
return ""; return "";
} }
public enum Version {
SASL, SASL_2
}
} }

View file

@ -7,6 +7,7 @@ public final class Namespace {
public static final String BLOCKING = "urn:xmpp:blocking"; public static final String BLOCKING = "urn:xmpp:blocking";
public static final String ROSTER = "jabber:iq:roster"; public static final String ROSTER = "jabber:iq:roster";
public static final String REGISTER = "jabber:iq:register"; public static final String REGISTER = "jabber:iq:register";
public static final String REGISTER_STREAM_FEATURE = "http://jabber.org/features/iq-register";
public static final String BYTE_STREAMS = "http://jabber.org/protocol/bytestreams"; public static final String BYTE_STREAMS = "http://jabber.org/protocol/bytestreams";
public static final String HTTP_UPLOAD = "urn:xmpp:http:upload:0"; public static final String HTTP_UPLOAD = "urn:xmpp:http:upload:0";
public static final String HTTP_UPLOAD_LEGACY = "urn:xmpp:http:upload"; public static final String HTTP_UPLOAD_LEGACY = "urn:xmpp:http:upload";
@ -15,6 +16,7 @@ public final class Namespace {
public static final String DATA = "jabber:x:data"; public static final String DATA = "jabber:x:data";
public static final String OOB = "jabber:x:oob"; public static final String OOB = "jabber:x:oob";
public static final String SASL = "urn:ietf:params:xml:ns:xmpp-sasl"; public static final String SASL = "urn:ietf:params:xml:ns:xmpp-sasl";
public static final String SASL_2 = "urn:xmpp:sasl:1";
public static final String TLS = "urn:ietf:params:xml:ns:xmpp-tls"; public static final String TLS = "urn:ietf:params:xml:ns:xmpp-tls";
public static final String PUBSUB = "http://jabber.org/protocol/pubsub"; public static final String PUBSUB = "http://jabber.org/protocol/pubsub";
public static final String PUBSUB_PUBLISH_OPTIONS = PUBSUB + "#publish-options"; public static final String PUBSUB_PUBLISH_OPTIONS = PUBSUB + "#publish-options";

View file

@ -848,40 +848,64 @@ public class XmppConnection implements Runnable {
private void processStreamFeatures(final Tag currentTag) throws IOException { private void processStreamFeatures(final Tag currentTag) throws IOException {
this.streamFeatures = tagReader.readElement(currentTag); this.streamFeatures = tagReader.readElement(currentTag);
final boolean isSecure = features.encryptionEnabled || Config.ALLOW_NON_TLS_CONNECTIONS || account.isOnion(); Log.d(Config.LOGTAG, this.streamFeatures.toString());
final boolean isSecure =
features.encryptionEnabled || Config.ALLOW_NON_TLS_CONNECTIONS || account.isOnion();
final boolean needsBinding = !isBound && !account.isOptionSet(Account.OPTION_REGISTER); final boolean needsBinding = !isBound && !account.isOptionSet(Account.OPTION_REGISTER);
if (this.streamFeatures.hasChild("starttls") && !features.encryptionEnabled) { if (this.streamFeatures.hasChild("starttls", Namespace.TLS)
&& !features.encryptionEnabled) {
sendStartTLS(); sendStartTLS();
} else if (this.streamFeatures.hasChild("register") && account.isOptionSet(Account.OPTION_REGISTER)) { } else if (this.streamFeatures.hasChild("register", Namespace.REGISTER_STREAM_FEATURE)
&& account.isOptionSet(Account.OPTION_REGISTER)) {
if (isSecure) { if (isSecure) {
register(); register();
} else { } else {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to find STARTTLS for registration process " + XmlHelper.printElementNames(this.streamFeatures)); Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
+ ": unable to find STARTTLS for registration process "
+ XmlHelper.printElementNames(this.streamFeatures));
throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER); throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER);
} }
} else if (!this.streamFeatures.hasChild("register") && account.isOptionSet(Account.OPTION_REGISTER)) { } else if (!this.streamFeatures.hasChild("register", Namespace.REGISTER_STREAM_FEATURE)
&& account.isOptionSet(Account.OPTION_REGISTER)) {
throw new StateChangingException(Account.State.REGISTRATION_NOT_SUPPORTED); throw new StateChangingException(Account.State.REGISTRATION_NOT_SUPPORTED);
} else if (this.streamFeatures.hasChild("mechanisms") && shouldAuthenticate && isSecure) { } else if (this.streamFeatures.hasChild("mechanisms", Namespace.SASL_2)
authenticate(); && shouldAuthenticate
} else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion) && streamId != null) { && isSecure) {
authenticate(SaslMechanism.Version.SASL_2);
} else if (this.streamFeatures.hasChild("mechanisms", Namespace.SASL)
&& shouldAuthenticate
&& isSecure) {
authenticate(SaslMechanism.Version.SASL);
} else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion)
&& streamId != null) {
if (Config.EXTENDED_SM_LOGGING) { if (Config.EXTENDED_SM_LOGGING) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": resuming after stanza #" + stanzasReceived); Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
+ ": resuming after stanza #"
+ stanzasReceived);
} }
final ResumePacket resume = new ResumePacket(this.streamId, stanzasReceived, smVersion); final ResumePacket resume = new ResumePacket(this.streamId, stanzasReceived, smVersion);
this.mSmCatchupMessageCounter.set(0); this.mSmCatchupMessageCounter.set(0);
this.mWaitingForSmCatchup.set(true); this.mWaitingForSmCatchup.set(true);
this.tagWriter.writeStanzaAsync(resume); this.tagWriter.writeStanzaAsync(resume);
} else if (needsBinding) { } else if (needsBinding) {
if (this.streamFeatures.hasChild("bind") && isSecure) { if (this.streamFeatures.hasChild("bind", Namespace.BIND) && isSecure) {
sendBindRequest(); sendBindRequest();
} else { } else {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to find bind feature " + XmlHelper.printElementNames(this.streamFeatures)); Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
+ ": unable to find bind feature "
+ XmlHelper.printElementNames(this.streamFeatures));
throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER); throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER);
} }
} }
} }
private void authenticate() throws IOException { private void authenticate(final SaslMechanism.Version version) throws IOException {
final List<String> mechanisms = extractMechanisms(streamFeatures.findChild("mechanisms")); final List<String> mechanisms = extractMechanisms(streamFeatures.findChild("mechanisms"));
final Element auth = new Element("auth", Namespace.SASL); final Element auth = new Element("auth", Namespace.SASL);
if (mechanisms.contains(External.MECHANISM) && account.getPrivateKeyAlias() != null) { if (mechanisms.contains(External.MECHANISM) && account.getPrivateKeyAlias() != null) {