[sasl] Avoid mechanisms that need a password when none is available

This commit is contained in:
Florian Schmaus 2021-03-25 15:01:15 +01:00
parent 72e11ebf71
commit 92f4aadfdc
4 changed files with 41 additions and 12 deletions

View File

@ -42,6 +42,7 @@ import org.jivesoftware.smack.sasl.core.ScramSha1PlusMechanism;
import org.jivesoftware.smack.sasl.packet.SaslNonza;
import org.jivesoftware.smack.sasl.packet.SaslNonza.SASLFailure;
import org.jivesoftware.smack.sasl.packet.SaslNonza.Success;
import org.jivesoftware.smack.util.StringUtils;
import org.jxmpp.jid.DomainBareJid;
import org.jxmpp.jid.EntityBareJid;
@ -184,7 +185,7 @@ public final class SASLAuthentication {
SASLMechanism authenticate(String username, String password, EntityBareJid authzid, SSLSession sslSession)
throws XMPPErrorException, SASLErrorException, IOException,
InterruptedException, SmackSaslException, NotConnectedException, NoResponseException {
final SASLMechanism mechanism = selectMechanism(authzid);
final SASLMechanism mechanism = selectMechanism(authzid, password);
final CallbackHandler callbackHandler = configuration.getCallbackHandler();
final String host = connection.getHost();
final DomainBareJid xmppServiceDomain = connection.getXMPPServiceDomain();
@ -312,35 +313,49 @@ public final class SASLAuthentication {
return lastUsedMech.getName();
}
private SASLMechanism selectMechanism(EntityBareJid authzid) throws SmackException.SmackSaslException {
private SASLMechanism selectMechanism(EntityBareJid authzid, String password) throws SmackException.SmackSaslException {
final boolean passwordAvailable = StringUtils.isNotEmpty(password);
Iterator<SASLMechanism> it = REGISTERED_MECHANISMS.iterator();
final List<String> serverMechanisms = getServerMechanisms();
if (serverMechanisms.isEmpty()) {
LOGGER.warning("Server did not report any SASL mechanisms");
}
List<String> skipReasons = new ArrayList<>();
// Iterate in SASL Priority order over registered mechanisms
while (it.hasNext()) {
SASLMechanism mechanism = it.next();
String mechanismName = mechanism.getName();
if (!serverMechanisms.contains(mechanismName)) {
continue;
}
synchronized (BLACKLISTED_MECHANISMS) {
if (BLACKLISTED_MECHANISMS.contains(mechanismName)) {
continue;
}
}
if (!configuration.isEnabledSaslMechanism(mechanismName)) {
continue;
}
if (authzid != null) {
if (!mechanism.authzidSupported()) {
LOGGER.fine("Skipping " + mechanism + " because authzid is required by not supported by this SASL mechanism");
if (authzid != null && !mechanism.authzidSupported()) {
skipReasons.add("Skipping " + mechanism + " because authzid is required by not supported by this SASL mechanism");
continue;
}
if (mechanism.requiresPassword() && !passwordAvailable) {
skipReasons.add("Skipping " + mechanism + " because a password is required for it, but none was provided to the connection configuration");
continue;
}
if (serverMechanisms.contains(mechanismName)) {
// Create a new instance of the SASLMechanism for every authentication attempt.
return mechanism.instanceForAuthentication(connection, configuration);
}
}
synchronized (BLACKLISTED_MECHANISMS) {
// @formatter:off
@ -349,7 +364,8 @@ public final class SASLAuthentication {
"Server announced mechanisms: " + serverMechanisms + ". " +
"Registered SASL mechanisms with Smack: " + REGISTERED_MECHANISMS + ". " +
"Enabled SASL mechanisms for this connection: " + configuration.getEnabledSaslMechanisms() + ". " +
"Blacklisted SASL mechanisms: " + BLACKLISTED_MECHANISMS + '.'
"Blacklisted SASL mechanisms: " + BLACKLISTED_MECHANISMS + ". " +
"Skip reasons: " + skipReasons
);
// @formatter;on
}

View File

@ -1,6 +1,6 @@
/**
*
* Copyright 2003-2007 Jive Software, 2014-2019 Florian Schmaus
* Copyright 2003-2007 Jive Software, 2014-2021 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -311,6 +311,10 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
return false;
}
public boolean requiresPassword() {
return true;
}
public boolean isAuthenticationSuccessful() {
return authenticationSuccessful;
}

View File

@ -65,4 +65,9 @@ public class SASLExternalMechanism extends SASLJavaXMechanism {
public SASLExternalMechanism newInstance() {
return new SASLExternalMechanism();
}
@Override
public boolean requiresPassword() {
return false;
}
}

View File

@ -76,4 +76,8 @@ public class SASLExternalMechanism extends SASLMechanism {
return true;
}
@Override
public boolean requiresPassword() {
return false;
}
}