1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-11-24 23:32:05 +01:00

Add allowEmptyOrNullUsername()

to ConnectionConfiguration.Builder().

And prepare SASL EXTERNAL for empty or null usernames.

Also clarify some parts regarding the user field.

Fixes SMACK-627
This commit is contained in:
Florian Schmaus 2015-01-10 11:18:07 +01:00
parent 50c7d0bc2c
commit 7e4e3699a1
4 changed files with 33 additions and 5 deletions

View file

@ -158,7 +158,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
protected final Map<String, PacketExtension> streamFeatures = new HashMap<String, PacketExtension>(); protected final Map<String, PacketExtension> streamFeatures = new HashMap<String, PacketExtension>();
/** /**
* The full JID of the authenticated user. * The full JID of the authenticated user, as returned by the resource binding response of the server.
* <p>
* It is important that we don't infer the user from the login() arguments and the configurations service name, as,
* for example, when SASL External is used, the username is not given to login but taken from the 'external'
* certificate.
* </p>
*/ */
protected String user; protected String user;
@ -431,7 +436,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
*/ */
public void login(String username, String password, String resource) throws XMPPException, public void login(String username, String password, String resource) throws XMPPException,
SmackException, IOException { SmackException, IOException {
if (StringUtils.isNullOrEmpty(username)) { if (!config.allowNullOrEmptyUsername && StringUtils.isNullOrEmpty(username)) {
throw new IllegalArgumentException("Username must not be null or empty"); throw new IllegalArgumentException("Username must not be null or empty");
} }
usedUsername = username; usedUsername = username;
@ -482,6 +487,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
Bind bindResource = Bind.newSet(resource); Bind bindResource = Bind.newSet(resource);
PacketCollector packetCollector = createPacketCollectorAndSend(new PacketIDFilter(bindResource), bindResource); PacketCollector packetCollector = createPacketCollectorAndSend(new PacketIDFilter(bindResource), bindResource);
Bind response = packetCollector.nextResultOrThrow(); Bind response = packetCollector.nextResultOrThrow();
// Set the connections user to the result of resource binding. It is important that we don't infer the user
// from the login() arguments and the configurations service name, as, for example, when SASL External is used,
// the username is not given to login but taken from the 'external' certificate.
user = response.getJid(); user = response.getJid();
serviceName = XmppStringUtils.parseDomain(user); serviceName = XmppStringUtils.parseDomain(user);

View file

@ -93,6 +93,8 @@ public abstract class ConnectionConfiguration {
// Holds the proxy information (such as proxyhost, proxyport, username, password etc) // Holds the proxy information (such as proxyhost, proxyport, username, password etc)
protected final ProxyInfo proxy; protected final ProxyInfo proxy;
protected final boolean allowNullOrEmptyUsername;
protected ConnectionConfiguration(Builder<?,?> builder) { protected ConnectionConfiguration(Builder<?,?> builder) {
if (builder.username != null) { if (builder.username != null) {
// Do partial version of nameprep on the username. // Do partial version of nameprep on the username.
@ -136,6 +138,7 @@ public abstract class ConnectionConfiguration {
legacySessionDisabled = builder.legacySessionDisabled; legacySessionDisabled = builder.legacySessionDisabled;
rosterStore = builder.rosterStore; rosterStore = builder.rosterStore;
debuggerEnabled = builder.debuggerEnabled; debuggerEnabled = builder.debuggerEnabled;
allowNullOrEmptyUsername = builder.allowEmptyOrNullUsername;
} }
/** /**
@ -405,6 +408,7 @@ public abstract class ConnectionConfiguration {
private String serviceName; private String serviceName;
private String host; private String host;
private int port = 5222; private int port = 5222;
private boolean allowEmptyOrNullUsername = false;
protected Builder() { protected Builder() {
} }
@ -647,6 +651,19 @@ public abstract class ConnectionConfiguration {
return getThis(); return getThis();
} }
/**
* Allow <code>null</code> or the empty String as username.
*
* Some SASL mechanisms (e.g. SASL External) may also signal the username (as "authorization identity"), in
* which case Smack should not throw an IllegalArgumentException when the username is not set.
*
* @return a reference to this builder.
*/
public B allowEmptyOrNullUsernames() {
allowEmptyOrNullUsername = true;
return getThis();
}
public abstract C build(); public abstract C build();
protected abstract B getThis(); protected abstract B getThis();

View file

@ -91,7 +91,10 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
protected XMPPConnection connection; protected XMPPConnection connection;
/** /**
* authcid * authcid, i.e. the username (localpart) of the XMPP connection trying to authenticated.
* <p>
* Not to be confused with the authzid.
* </p>
*/ */
protected String authenticationId; protected String authenticationId;

View file

@ -20,7 +20,7 @@ import javax.security.auth.callback.CallbackHandler;
import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.sasl.SASLMechanism; import org.jivesoftware.smack.sasl.SASLMechanism;
import org.jivesoftware.smack.util.StringUtils;
import org.jxmpp.util.XmppStringUtils; import org.jxmpp.util.XmppStringUtils;
/** /**
@ -39,7 +39,7 @@ public class SASLExternalMechanism extends SASLMechanism {
@Override @Override
protected byte[] getAuthenticationText() throws SmackException { protected byte[] getAuthenticationText() throws SmackException {
if (authenticationId == null) { if (StringUtils.isNullOrEmpty(authenticationId)) {
return null; return null;
} }