SaslMechanism.java

  1package eu.siacs.conversations.crypto.sasl;
  2
  3import com.google.common.base.Strings;
  4
  5import java.util.Collection;
  6
  7import eu.siacs.conversations.entities.Account;
  8import eu.siacs.conversations.xml.Element;
  9import eu.siacs.conversations.xml.Namespace;
 10
 11public abstract class SaslMechanism {
 12
 13    protected final Account account;
 14
 15    protected SaslMechanism(final Account account) {
 16        this.account = account;
 17    }
 18
 19    /**
 20     * The priority is used to pin the authentication mechanism. If authentication fails, it MAY be
 21     * retried with another mechanism of the same priority, but MUST NOT be tried with a mechanism
 22     * of lower priority (to prevent downgrade attacks).
 23     *
 24     * @return An arbitrary int representing the priority
 25     */
 26    public abstract int getPriority();
 27
 28    public abstract String getMechanism();
 29
 30    public String getClientFirstMessage() {
 31        return "";
 32    }
 33
 34    public String getResponse(final String challenge) throws AuthenticationException {
 35        return "";
 36    }
 37
 38    protected enum State {
 39        INITIAL,
 40        AUTH_TEXT_SENT,
 41        RESPONSE_SENT,
 42        VALID_SERVER_RESPONSE,
 43    }
 44
 45    public enum Version {
 46        SASL,
 47        SASL_2;
 48
 49        public static Version of(final Element element) {
 50            switch (Strings.nullToEmpty(element.getNamespace())) {
 51                case Namespace.SASL:
 52                    return SASL;
 53                case Namespace.SASL_2:
 54                    return SASL_2;
 55                default:
 56                    throw new IllegalArgumentException("Unrecognized SASL namespace");
 57            }
 58        }
 59    }
 60
 61    public static class AuthenticationException extends Exception {
 62        public AuthenticationException(final String message) {
 63            super(message);
 64        }
 65
 66        public AuthenticationException(final Exception inner) {
 67            super(inner);
 68        }
 69
 70        public AuthenticationException(final String message, final Exception exception) {
 71            super(message, exception);
 72        }
 73    }
 74
 75    public static class InvalidStateException extends AuthenticationException {
 76        public InvalidStateException(final String message) {
 77            super(message);
 78        }
 79
 80        public InvalidStateException(final State state) {
 81            this("Invalid state: " + state.toString());
 82        }
 83    }
 84
 85    public static final class Factory {
 86
 87        private final Account account;
 88
 89        public Factory(final Account account) {
 90            this.account = account;
 91        }
 92
 93        public SaslMechanism of(final Collection<String> mechanisms) {
 94            if (mechanisms.contains(External.MECHANISM) && account.getPrivateKeyAlias() != null) {
 95                return new External(account);
 96            } else if (mechanisms.contains(ScramSha512.MECHANISM)) {
 97                return new ScramSha512(account);
 98            } else if (mechanisms.contains(ScramSha256.MECHANISM)) {
 99                return new ScramSha256(account);
100            } else if (mechanisms.contains(ScramSha1.MECHANISM)) {
101                return new ScramSha1(account);
102            } else if (mechanisms.contains(Plain.MECHANISM)
103                    && !account.getServer().equals("nimbuzz.com")) {
104                return new Plain(account);
105            } else if (mechanisms.contains(DigestMd5.MECHANISM)) {
106                return new DigestMd5(account);
107            } else if (mechanisms.contains(Anonymous.MECHANISM)) {
108                return new Anonymous(account);
109            } else {
110                return null;
111            }
112        }
113    }
114}