1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-10-31 17:25:58 +01:00

Improve Exceptions (SMACK-426)

This commit is contained in:
Florian Schmaus 2014-03-17 21:06:45 +01:00
parent 9c8d7af3bf
commit c592b4f046
9 changed files with 103 additions and 57 deletions

View file

@ -18,6 +18,7 @@
package org.jivesoftware.smack; package org.jivesoftware.smack;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.ResourceBindingNotOfferedException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.packet.Bind; import org.jivesoftware.smack.packet.Bind;
import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Packet;
@ -210,9 +211,10 @@ public class SASLAuthentication {
* @throws XMPPErrorException * @throws XMPPErrorException
* @throws NoResponseException * @throws NoResponseException
* @throws SASLErrorException * @throws SASLErrorException
* @throws ResourceBindingNotOfferedException
*/ */
public String authenticate(String resource, CallbackHandler cbh) throws IOException, public String authenticate(String resource, CallbackHandler cbh) throws IOException,
NoResponseException, XMPPErrorException, SASLErrorException { NoResponseException, XMPPErrorException, SASLErrorException, ResourceBindingNotOfferedException {
// Locate the SASLMechanism to use // Locate the SASLMechanism to use
String selectedMechanism = null; String selectedMechanism = null;
for (String mechanism : mechanismsPreferences) { for (String mechanism : mechanismsPreferences) {
@ -265,8 +267,7 @@ public class SASLAuthentication {
return bindResourceAndEstablishSession(resource); return bindResourceAndEstablishSession(resource);
} }
else { else {
// SASL authentication failed throw new NoResponseException();
throw new SaslException();
} }
} }
@ -352,8 +353,7 @@ public class SASLAuthentication {
return bindResourceAndEstablishSession(resource); return bindResourceAndEstablishSession(resource);
} }
else { else {
// SASL authentication failed throw new NoResponseException();
throw new SaslException();
} }
} }
else { else {
@ -404,11 +404,12 @@ public class SASLAuthentication {
return bindResourceAndEstablishSession(null); return bindResourceAndEstablishSession(null);
} }
else { else {
throw new SaslException(); throw new NoResponseException();
} }
} }
private String bindResourceAndEstablishSession(String resource) throws NoResponseException, XMPPErrorException { private String bindResourceAndEstablishSession(String resource) throws XMPPErrorException,
ResourceBindingNotOfferedException, NoResponseException {
// Wait until server sends response containing the <bind> element // Wait until server sends response containing the <bind> element
synchronized (this) { synchronized (this) {
if (!resourceBinded) { if (!resourceBinded) {
@ -424,7 +425,7 @@ public class SASLAuthentication {
if (!resourceBinded) { if (!resourceBinded) {
// Server never offered resource binding, which is REQURIED in XMPP client and server // Server never offered resource binding, which is REQURIED in XMPP client and server
// implementations as per RFC6120 7.2 // implementations as per RFC6120 7.2
throw new IllegalStateException("Resource binding not offered by server"); throw new ResourceBindingNotOfferedException();
} }
Bind bindResource = new Bind(); Bind bindResource = new Bind();

View file

@ -152,8 +152,45 @@ public class SmackException extends Exception {
*/ */
private static final long serialVersionUID = 4713404802621452016L; private static final long serialVersionUID = 4713404802621452016L;
public FeatureNotSupportedException(String message) { private final String feature;
super(message); private final String jid;
public FeatureNotSupportedException(String feature) {
this(feature, null);
}
public FeatureNotSupportedException(String feature, String jid) {
super(feature + " not supported" + (jid == null ? "" : " by '" + jid + "'"));
this.jid = jid;
this.feature = feature;
}
/**
* Get the feature which is not supported.
*
* @return the feature which is not supported
*/
public String getFeature() {
return feature;
}
/**
* Get JID which does not support the feature. The JID can be null in cases when there are
* multiple JIDs queried for this feature.
*
* @return the JID which does not support the feature, or null
*/
public String getJid() {
return jid;
} }
} }
public static class ResourceBindingNotOfferedException extends SmackException {
/**
*
*/
private static final long serialVersionUID = 2346934138253437571L;
}
} }

View file

@ -16,6 +16,9 @@
*/ */
package org.jivesoftware.smack.sasl; package org.jivesoftware.smack.sasl;
import java.util.logging.Level;
import java.util.logging.Logger;
public enum SASLError { public enum SASLError {
aborted, aborted,
@ -29,6 +32,7 @@ public enum SASLError {
not_authorized, not_authorized,
temporary_auth_failure; temporary_auth_failure;
private static final Logger LOGGER = Logger.getLogger(SASLError.class.getName());
@Override @Override
public String toString() { public String toString() {
return this.name().replace('_', '-'); return this.name().replace('_', '-');
@ -36,10 +40,12 @@ public enum SASLError {
public static SASLError fromString(String string) { public static SASLError fromString(String string) {
string = string.replace('-', '_'); string = string.replace('-', '_');
for (SASLError error : SASLError.values()) { SASLError saslError = null;
if (error.name().equals(string)) try {
return error; saslError = SASLError.valueOf(string);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Could not transform string '" + string + "' to SASLError", e);
} }
return null; return saslError;
} }
} }

View file

@ -34,12 +34,14 @@ public class SASLErrorException extends XMPPException {
private final Map<String,String> texts; private final Map<String,String> texts;
public SASLErrorException(String mechanism, SASLFailure saslFailure) { public SASLErrorException(String mechanism, SASLFailure saslFailure) {
super("SASLError using " + mechanism + ": " + saslFailure);
this.mechanism = mechanism; this.mechanism = mechanism;
this.saslFailure = saslFailure; this.saslFailure = saslFailure;
this.texts = new HashMap<String, String>(); this.texts = new HashMap<String, String>();
} }
public SASLErrorException(String mechanism, SASLFailure saslFailure, Map<String,String> texts) { public SASLErrorException(String mechanism, SASLFailure saslFailure, Map<String,String> texts) {
super("SASLError using " + mechanism + ": " + saslFailure);
this.mechanism = mechanism; this.mechanism = mechanism;
this.saslFailure = saslFailure; this.saslFailure = saslFailure;
this.texts = texts; this.texts = texts;

View file

@ -113,7 +113,7 @@ public class MultipleRecipientManager {
(replyRoom != null && replyRoom.trim().length() > 0)) { (replyRoom != null && replyRoom.trim().length() > 0)) {
// Some specified JEP-33 features were requested so throw an exception alerting // Some specified JEP-33 features were requested so throw an exception alerting
// the user that this features are not available // the user that this features are not available
throw new FeatureNotSupportedException("Extended Stanza Addressing not supported by server"); throw new FeatureNotSupportedException("Extended Stanza Addressing");
} }
// Send the packet to each individual recipient // Send the packet to each individual recipient
sendToIndividualRecipients(connection, packet, to, cc, bcc); sendToIndividualRecipients(connection, packet, to, cc, bcc);

View file

@ -211,9 +211,11 @@ public class InBandBytestreamSession implements BytestreamSession {
connection.createPacketCollectorAndSend(close).nextResultOrThrow(); connection.createPacketCollectorAndSend(close).nextResultOrThrow();
} }
catch (Exception e) { catch (Exception e) {
// Sadly we are unable to wrap the exception within the IOException, because the // Sadly we are unable to use the IOException(Throwable) constructor because this
// IOException(String,Throwable) constructor is only support from Android API 9 on. // constructor is only supported from Android API 9 on.
throw new IOException(); IOException ioException = new IOException();
ioException.initCause(e);
throw ioException;
} }
this.inputStream.cleanup(); this.inputStream.cleanup();
@ -769,9 +771,11 @@ public class InBandBytestreamSession implements BytestreamSession {
// close session unless it is already closed // close session unless it is already closed
if (!this.isClosed) { if (!this.isClosed) {
InBandBytestreamSession.this.close(); InBandBytestreamSession.this.close();
// Sadly we are unable to wrap the exception within the IOException, because the // Sadly we are unable to use the IOException(Throwable) constructor because this
// IOException(String,Throwable) constructor is only support from Android API 9 on. // constructor is only supported from Android API 9 on.
throw new IOException(); IOException ioException = new IOException();
ioException.initCause(e);
throw ioException;
} }
} }

View file

@ -32,6 +32,7 @@ import java.util.concurrent.TimeoutException;
import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.AbstractConnectionListener;
import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.FeatureNotSupportedException;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
@ -436,7 +437,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
XMPPErrorException discoveryException = null; XMPPErrorException discoveryException = null;
// check if target supports SOCKS5 Bytestream // check if target supports SOCKS5 Bytestream
if (!supportsSocks5(targetJID)) { if (!supportsSocks5(targetJID)) {
throw new SmackException(targetJID + " doesn't support SOCKS5 Bytestream"); throw new FeatureNotSupportedException("SOCKS5 Bytestream", targetJID);
} }
List<String> proxies = new ArrayList<String>(); List<String> proxies = new ArrayList<String>();

View file

@ -144,8 +144,9 @@ class Socks5Client {
* @return <code>true</code> if if a stream could be established, otherwise <code>false</code>. * @return <code>true</code> if if a stream could be established, otherwise <code>false</code>.
* If <code>false</code> is returned the given Socket should be closed. * If <code>false</code> is returned the given Socket should be closed.
* @throws SmackException * @throws SmackException
* @throws IOException
*/ */
protected boolean establish(Socket socket) throws SmackException { protected boolean establish(Socket socket) throws SmackException, IOException {
byte[] connectionRequest; byte[] connectionRequest;
byte[] connectionResponse; byte[] connectionResponse;
@ -153,39 +154,35 @@ class Socks5Client {
* use DataInputStream/DataOutpuStream to assure read and write is completed in a single * use DataInputStream/DataOutpuStream to assure read and write is completed in a single
* statement * statement
*/ */
try { DataInputStream in = new DataInputStream(socket.getInputStream());
DataInputStream in = new DataInputStream(socket.getInputStream()); DataOutputStream out = new DataOutputStream(socket.getOutputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
// authentication negotiation // authentication negotiation
byte[] cmd = new byte[3]; byte[] cmd = new byte[3];
cmd[0] = (byte) 0x05; // protocol version 5 cmd[0] = (byte) 0x05; // protocol version 5
cmd[1] = (byte) 0x01; // number of authentication methods supported cmd[1] = (byte) 0x01; // number of authentication methods supported
cmd[2] = (byte) 0x00; // authentication method: no-authentication required cmd[2] = (byte) 0x00; // authentication method: no-authentication required
out.write(cmd); out.write(cmd);
out.flush(); out.flush();
byte[] response = new byte[2]; byte[] response = new byte[2];
in.readFully(response); in.readFully(response);
// check if server responded with correct version and no-authentication method // check if server responded with correct version and no-authentication method
if (response[0] != (byte) 0x05 || response[1] != (byte) 0x00) { if (response[0] != (byte) 0x05 || response[1] != (byte) 0x00) {
return false; return false;
}
// request SOCKS5 connection with given address/digest
connectionRequest = createSocks5ConnectRequest();
out.write(connectionRequest);
out.flush();
// receive response
connectionResponse = Socks5Utils.receiveSocks5Message(in);
}
catch (IOException e) {
throw new SmackException(e);
} }
// request SOCKS5 connection with given address/digest
connectionRequest = createSocks5ConnectRequest();
out.write(connectionRequest);
out.flush();
// receive response
connectionResponse = Socks5Utils.receiveSocks5Message(in);
// verify response // verify response
connectionRequest[1] = (byte) 0x00; // set expected return status to 0 connectionRequest[1] = (byte) 0x00; // set expected return status to 0
return Arrays.equals(connectionRequest, connectionResponse); return Arrays.equals(connectionRequest, connectionResponse);

View file

@ -25,6 +25,7 @@ import java.io.OutputStream;
import java.net.ConnectException; import java.net.ConnectException;
import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.FeatureNotSupportedException;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.XMPPException.XMPPErrorException;
@ -152,13 +153,10 @@ public class Socks5ByteStreamManagerTest {
fail("exception should be thrown"); fail("exception should be thrown");
} }
catch (SmackException e) { catch (FeatureNotSupportedException e) {
assertTrue(e.getMessage().contains("doesn't support SOCKS5 Bytestream")); assertTrue(e.getFeature().equals("SOCKS5 Bytestream"));
} assertTrue(e.getJid().equals(targetJID));
catch (IOException e) { } catch(Exception e) {
fail(e.getMessage());
}
catch (InterruptedException e) {
fail(e.getMessage()); fail(e.getMessage());
} }