mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-12-23 13:07:59 +01:00
1. Added anonymous authentication. SMACK-84
2. Fixed possible delay waiting for server reply. SMACK-85 git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@2783 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
6d6fdcf9b6
commit
b94d041bba
1 changed files with 135 additions and 1 deletions
|
@ -24,6 +24,7 @@ import org.jivesoftware.smack.filter.PacketIDFilter;
|
|||
import org.jivesoftware.smack.packet.Bind;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Session;
|
||||
import org.jivesoftware.smack.sasl.SASLAnonymous;
|
||||
import org.jivesoftware.smack.sasl.SASLMechanism;
|
||||
import org.jivesoftware.smack.sasl.SASLPlainMechanism;
|
||||
|
||||
|
@ -68,6 +69,7 @@ public class SASLAuthentication implements UserAuthentication {
|
|||
* Boolean indicating if SASL negotiation has finished and was successful.
|
||||
*/
|
||||
private boolean saslNegotiated = false;
|
||||
private boolean resourceBinded = false;
|
||||
private boolean sessionSupported = false;
|
||||
|
||||
static {
|
||||
|
@ -121,6 +123,45 @@ public class SASLAuthentication implements UserAuthentication {
|
|||
this.connection = connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the server offered ANONYMOUS SASL as a way to authenticate users.
|
||||
*
|
||||
* @return true if the server offered ANONYMOUS SASL as a way to authenticate users.
|
||||
*/
|
||||
public boolean hasAnonymousAuthentication() {
|
||||
return serverMechanisms.contains("ANONYMOUS");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the server offered SASL authentication besides ANONYMOUS SASL.
|
||||
*
|
||||
* @return true if the server offered SASL authentication besides ANONYMOUS SASL.
|
||||
*/
|
||||
public boolean hasNonAnonymousAuthentication() {
|
||||
if (!serverMechanisms.isEmpty()) {
|
||||
// Check that anonymous sasl is not the only supported mechanism
|
||||
if (serverMechanisms.size() == 1) {
|
||||
return !hasAnonymousAuthentication();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs SASL authentication of the specified user. If SASL authentication was successful
|
||||
* then resource binding and session establishment will be performed. This method will return
|
||||
* the full JID provided by the server while binding a resource to the connection.<p>
|
||||
*
|
||||
* The server may assign a full JID with a username or resource different than the requested
|
||||
* by this method.
|
||||
*
|
||||
* @param username the username that is authenticating with the server.
|
||||
* @param password the password to send to the server.
|
||||
* @param resource the desired resource.
|
||||
* @return the full JID provided by the server while binding a resource to the connection.
|
||||
* @throws XMPPException if an error occures while authenticating.
|
||||
*/
|
||||
public String authenticate(String username, String password, String resource)
|
||||
throws XMPPException {
|
||||
// Locate the SASLMechanism to use
|
||||
|
@ -221,6 +262,98 @@ public class SASLAuthentication implements UserAuthentication {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs ANONYMOUS SASL authentication. If SASL authentication was successful
|
||||
* then resource binding and session establishment will be performed. This method will return
|
||||
* the full JID provided by the server while binding a resource to the connection.<p>
|
||||
*
|
||||
* The server will assign a full JID with a randomly generated resource and possibly with
|
||||
* no username.
|
||||
*
|
||||
* @return the full JID provided by the server while binding a resource to the connection.
|
||||
* @throws XMPPException if an error occures while authenticating.
|
||||
*/
|
||||
public String authenticateAnonymously() throws XMPPException {
|
||||
try {
|
||||
currentMechanism = new SASLAnonymous(this);
|
||||
currentMechanism.authenticate(null, null, null);
|
||||
|
||||
// Wait until SASL negotiation finishes
|
||||
synchronized (this) {
|
||||
if (!saslNegotiated) {
|
||||
try {
|
||||
wait(5000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (saslNegotiated) {
|
||||
// Bind a resource for this connection and
|
||||
return bindResourceAndEstablishSession(null);
|
||||
}
|
||||
else {
|
||||
return new NonSASLAuthentication(connection).authenticateAnonymously();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return new NonSASLAuthentication(connection).authenticateAnonymously();
|
||||
}
|
||||
}
|
||||
|
||||
private String bindResourceAndEstablishSession(String resource) throws IOException,
|
||||
XMPPException {
|
||||
// We now need to bind a resource for the connection
|
||||
// Open a new stream and wait for the response
|
||||
connection.packetWriter.openStream();
|
||||
|
||||
// Wait until server sends response containing the <bind> element
|
||||
synchronized (this) {
|
||||
if (!resourceBinded) {
|
||||
try {
|
||||
wait(30000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bind bindResource = new Bind();
|
||||
bindResource.setResource(resource);
|
||||
|
||||
PacketCollector collector = connection
|
||||
.createPacketCollector(new PacketIDFilter(bindResource.getPacketID()));
|
||||
// Send the packet
|
||||
connection.sendPacket(bindResource);
|
||||
// Wait up to a certain number of seconds for a response from the server.
|
||||
Bind response = (Bind) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
collector.cancel();
|
||||
if (response == null) {
|
||||
throw new XMPPException("No response from the server.");
|
||||
}
|
||||
// If the server replied with an error, throw an exception.
|
||||
else if (response.getType() == IQ.Type.ERROR) {
|
||||
throw new XMPPException(response.getError());
|
||||
}
|
||||
String userJID = response.getJid();
|
||||
|
||||
if (sessionSupported) {
|
||||
Session session = new Session();
|
||||
collector = connection.createPacketCollector(new PacketIDFilter(session.getPacketID()));
|
||||
// Send the packet
|
||||
connection.sendPacket(session);
|
||||
// Wait up to a certain number of seconds for a response from the server.
|
||||
IQ ack = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
||||
collector.cancel();
|
||||
if (ack == null) {
|
||||
throw new XMPPException("No response from the server.");
|
||||
}
|
||||
// If the server replied with an error, throw an exception.
|
||||
else if (ack.getType() == IQ.Type.ERROR) {
|
||||
throw new XMPPException(ack.getError());
|
||||
}
|
||||
}
|
||||
return userJID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the available SASL mechanism reported by the server. The server will report the
|
||||
* available SASL mechanism once the TLS negotiation was successful. This information is
|
||||
|
@ -251,8 +384,8 @@ public class SASLAuthentication implements UserAuthentication {
|
|||
* would be to bind the resource.
|
||||
*/
|
||||
void authenticated() {
|
||||
saslNegotiated = true;
|
||||
synchronized (this) {
|
||||
saslNegotiated = true;
|
||||
// Wake up the thread that is waiting in the #authenticate method
|
||||
notify();
|
||||
}
|
||||
|
@ -264,6 +397,7 @@ public class SASLAuthentication implements UserAuthentication {
|
|||
*/
|
||||
void bindingRequired() {
|
||||
synchronized (this) {
|
||||
resourceBinded = true;
|
||||
// Wake up the thread that is waiting in the #authenticate method
|
||||
notify();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue