mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-26 16:22:06 +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.Bind;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.packet.Session;
|
import org.jivesoftware.smack.packet.Session;
|
||||||
|
import org.jivesoftware.smack.sasl.SASLAnonymous;
|
||||||
import org.jivesoftware.smack.sasl.SASLMechanism;
|
import org.jivesoftware.smack.sasl.SASLMechanism;
|
||||||
import org.jivesoftware.smack.sasl.SASLPlainMechanism;
|
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.
|
* Boolean indicating if SASL negotiation has finished and was successful.
|
||||||
*/
|
*/
|
||||||
private boolean saslNegotiated = false;
|
private boolean saslNegotiated = false;
|
||||||
|
private boolean resourceBinded = false;
|
||||||
private boolean sessionSupported = false;
|
private boolean sessionSupported = false;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -121,6 +123,45 @@ public class SASLAuthentication implements UserAuthentication {
|
||||||
this.connection = connection;
|
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)
|
public String authenticate(String username, String password, String resource)
|
||||||
throws XMPPException {
|
throws XMPPException {
|
||||||
// Locate the SASLMechanism to use
|
// 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
|
* 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
|
* 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.
|
* would be to bind the resource.
|
||||||
*/
|
*/
|
||||||
void authenticated() {
|
void authenticated() {
|
||||||
saslNegotiated = true;
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
saslNegotiated = true;
|
||||||
// Wake up the thread that is waiting in the #authenticate method
|
// Wake up the thread that is waiting in the #authenticate method
|
||||||
notify();
|
notify();
|
||||||
}
|
}
|
||||||
|
@ -264,6 +397,7 @@ public class SASLAuthentication implements UserAuthentication {
|
||||||
*/
|
*/
|
||||||
void bindingRequired() {
|
void bindingRequired() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
resourceBinded = true;
|
||||||
// Wake up the thread that is waiting in the #authenticate method
|
// Wake up the thread that is waiting in the #authenticate method
|
||||||
notify();
|
notify();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue