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

View File

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

View File

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