reset quick start after invalid mechanism

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java                | 31 
src/main/java/im/conversations/android/xmpp/model/AuthenticationFailure.java | 18 
src/main/java/im/conversations/android/xmpp/model/sasl/Failure.java          | 11 
src/main/java/im/conversations/android/xmpp/model/sasl/SaslError.java        | 89 
src/main/java/im/conversations/android/xmpp/model/sasl2/Authenticate.java    |  3 
src/main/java/im/conversations/android/xmpp/model/sasl2/Failure.java         | 12 
6 files changed, 156 insertions(+), 8 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java πŸ”—

@@ -63,6 +63,7 @@ import eu.siacs.conversations.xmpp.bind.Bind2;
 import eu.siacs.conversations.xmpp.forms.Data;
 import eu.siacs.conversations.xmpp.jingle.OnJinglePacketReceived;
 
+import im.conversations.android.xmpp.model.AuthenticationFailure;
 import im.conversations.android.xmpp.model.AuthenticationRequest;
 import im.conversations.android.xmpp.model.AuthenticationStreamFeature;
 import im.conversations.android.xmpp.model.StreamElement;
@@ -75,8 +76,10 @@ import im.conversations.android.xmpp.model.fast.Fast;
 import im.conversations.android.xmpp.model.fast.RequestToken;
 import im.conversations.android.xmpp.model.jingle.Jingle;
 import im.conversations.android.xmpp.model.sasl.Auth;
+import im.conversations.android.xmpp.model.sasl.Failure;
 import im.conversations.android.xmpp.model.sasl.Mechanisms;
 import im.conversations.android.xmpp.model.sasl.Response;
+import im.conversations.android.xmpp.model.sasl.SaslError;
 import im.conversations.android.xmpp.model.sasl.Success;
 import im.conversations.android.xmpp.model.sasl2.Authenticate;
 import im.conversations.android.xmpp.model.sasl2.Authentication;
@@ -616,8 +619,13 @@ public class XmppConnection implements Runnable {
                 if (processSuccess(success)) {
                     break;
                 }
-            } else if (nextTag.isStart("failure")) {
-                final Element failure = tagReader.readElement(nextTag);
+            } else if (nextTag.isStart("failure", Namespace.SASL)) {
+                final var failure = tagReader.readElement(nextTag, Failure.class);
+                processFailure(failure);
+            } else if (nextTag.isStart("failure", Namespace.SASL_2)) {
+                final var failure =
+                        tagReader.readElement(
+                                nextTag, im.conversations.android.xmpp.model.sasl2.Failure.class);
                 processFailure(failure);
             } else if (nextTag.isStart("continue", Namespace.SASL_2)) {
                 // two step sasl2 - we don’t support this yet
@@ -962,7 +970,7 @@ public class XmppConnection implements Runnable {
         }
     }
 
-    private void processFailure(final Element failure) throws IOException {
+    private void processFailure(final AuthenticationFailure failure) throws IOException {
         final SaslMechanism.Version version;
         try {
             version = SaslMechanism.Version.of(failure);
@@ -976,10 +984,21 @@ public class XmppConnection implements Runnable {
             account.resetFastToken();
             mXmppConnectionService.databaseBackend.updateAccount(account);
         }
-        if (failure.hasChild("temporary-auth-failure")) {
+        final var errorCondition = failure.getErrorCondition();
+        if (errorCondition instanceof SaslError.InvalidMechanism
+                || errorCondition instanceof SaslError.MechanismTooWeak) {
+            Log.d(
+                    Config.LOGTAG,
+                    account.getJid().asBareJid()
+                            + ": invalid or too weak mechanism. resetting quick start");
+            if (account.setOption(Account.OPTION_QUICKSTART_AVAILABLE, false)) {
+                mXmppConnectionService.databaseBackend.updateAccount(account);
+            }
+            throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER);
+        } else if (errorCondition instanceof SaslError.TemporaryAuthFailure) {
             throw new StateChangingException(Account.State.TEMPORARY_AUTH_FAILURE);
-        } else if (failure.hasChild("account-disabled")) {
-            final String text = failure.findChildContent("text");
+        } else if (errorCondition instanceof SaslError.AccountDisabled) {
+            final String text = failure.getText();
             if (Strings.isNullOrEmpty(text)) {
                 throw new StateChangingException(Account.State.UNAUTHORIZED);
             }

src/main/java/im/conversations/android/xmpp/model/AuthenticationFailure.java πŸ”—

@@ -0,0 +1,18 @@
+package im.conversations.android.xmpp.model;
+
+import im.conversations.android.xmpp.model.sasl.SaslError;
+
+public abstract class AuthenticationFailure extends StreamElement {
+
+    protected AuthenticationFailure(Class<? extends AuthenticationFailure> clazz) {
+        super(clazz);
+    }
+
+    public SaslError getErrorCondition() {
+        return this.getExtension(SaslError.class);
+    }
+
+    public String getText() {
+        return this.findChildContent("text");
+    }
+}

src/main/java/im/conversations/android/xmpp/model/sasl/Failure.java πŸ”—

@@ -0,0 +1,11 @@
+package im.conversations.android.xmpp.model.sasl;
+
+import im.conversations.android.annotation.XmlElement;
+import im.conversations.android.xmpp.model.AuthenticationFailure;
+
+@XmlElement
+public class Failure extends AuthenticationFailure {
+    public Failure() {
+        super(Failure.class);
+    }
+}

src/main/java/im/conversations/android/xmpp/model/sasl/SaslError.java πŸ”—

@@ -0,0 +1,89 @@
+package im.conversations.android.xmpp.model.sasl;
+
+import im.conversations.android.annotation.XmlElement;
+import im.conversations.android.xmpp.model.Extension;
+
+public class SaslError extends Extension {
+
+    private SaslError(final Class<? extends SaslError> clazz) {
+        super(clazz);
+    }
+
+    @XmlElement
+    public static class Aborted extends SaslError {
+        public Aborted() {
+            super(Aborted.class);
+        }
+    }
+
+    @XmlElement
+    public static class AccountDisabled extends SaslError {
+        public AccountDisabled() {
+            super(AccountDisabled.class);
+        }
+    }
+
+    @XmlElement
+    public static class CredentialsExpired extends SaslError {
+        public CredentialsExpired() {
+            super(CredentialsExpired.class);
+        }
+    }
+
+    @XmlElement
+    public static class EncryptionRequired extends SaslError {
+        public EncryptionRequired() {
+            super(EncryptionRequired.class);
+        }
+    }
+
+    @XmlElement
+    public static class IncorrectEncoding extends SaslError {
+        public IncorrectEncoding() {
+            super(IncorrectEncoding.class);
+        }
+    }
+
+    @XmlElement
+    public static class InvalidAuthzid extends SaslError {
+        public InvalidAuthzid() {
+            super(InvalidAuthzid.class);
+        }
+    }
+
+    @XmlElement
+    public static class InvalidMechanism extends SaslError {
+        public InvalidMechanism() {
+            super(InvalidMechanism.class);
+        }
+    }
+
+    @XmlElement
+    public static class MalformedRequest extends SaslError {
+        public MalformedRequest() {
+            super(MalformedRequest.class);
+        }
+    }
+
+    @XmlElement
+    public static class MechanismTooWeak extends SaslError {
+        public MechanismTooWeak() {
+            super(MechanismTooWeak.class);
+        }
+    }
+
+    @XmlElement
+    public static class NotAuthorized extends SaslError {
+
+        public NotAuthorized() {
+            super(NotAuthorized.class);
+        }
+    }
+
+    @XmlElement
+    public static class TemporaryAuthFailure extends SaslError {
+        public TemporaryAuthFailure() {
+            super(TemporaryAuthFailure.class);
+        }
+    }
+}

src/main/java/im/conversations/android/xmpp/model/sasl2/Authenticate.java πŸ”—

@@ -1,10 +1,9 @@
 package im.conversations.android.xmpp.model.sasl2;
 
 import eu.siacs.conversations.crypto.sasl.SaslMechanism;
-import eu.siacs.conversations.xmpp.XmppConnection;
+
 import im.conversations.android.annotation.XmlElement;
 import im.conversations.android.xmpp.model.AuthenticationRequest;
-import im.conversations.android.xmpp.model.StreamElement;
 
 @XmlElement
 public class Authenticate extends AuthenticationRequest {

src/main/java/im/conversations/android/xmpp/model/sasl2/Failure.java πŸ”—

@@ -0,0 +1,12 @@
+package im.conversations.android.xmpp.model.sasl2;
+
+import im.conversations.android.annotation.XmlElement;
+import im.conversations.android.xmpp.model.AuthenticationFailure;
+
+@XmlElement
+public class Failure extends AuthenticationFailure {
+
+    public Failure() {
+        super(Failure.class);
+    }
+}