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>();
/**
* 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;
@ -431,7 +436,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
*/
public void login(String username, String password, String resource) throws XMPPException,
SmackException, IOException {
if (StringUtils.isNullOrEmpty(username)) {
if (!config.allowNullOrEmptyUsername && StringUtils.isNullOrEmpty(username)) {
throw new IllegalArgumentException("Username must not be null or empty");
}
usedUsername = username;
@ -482,6 +487,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
Bind bindResource = Bind.newSet(resource);
PacketCollector packetCollector = createPacketCollectorAndSend(new PacketIDFilter(bindResource), bindResource);
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();
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)
protected final ProxyInfo proxy;
protected final boolean allowNullOrEmptyUsername;
protected ConnectionConfiguration(Builder<?,?> builder) {
if (builder.username != null) {
// Do partial version of nameprep on the username.
@ -136,6 +138,7 @@ public abstract class ConnectionConfiguration {
legacySessionDisabled = builder.legacySessionDisabled;
rosterStore = builder.rosterStore;
debuggerEnabled = builder.debuggerEnabled;
allowNullOrEmptyUsername = builder.allowEmptyOrNullUsername;
}
/**
@ -405,6 +408,7 @@ public abstract class ConnectionConfiguration {
private String serviceName;
private String host;
private int port = 5222;
private boolean allowEmptyOrNullUsername = false;
protected Builder() {
}
@ -647,6 +651,19 @@ public abstract class ConnectionConfiguration {
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();
protected abstract B getThis();

View File

@ -91,7 +91,10 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
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;

View File

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