1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-09-29 03:09:33 +02:00

1. Added support for TLS. SMACK-76

2. Added support for SASL. SMACK-24

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@2732 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
Gaston Dombiak 2005-08-27 02:29:04 +00:00 committed by gato
parent 59e393e2ef
commit ad6be5887c
2 changed files with 142 additions and 25 deletions

View file

@ -20,17 +20,16 @@
package org.jivesoftware.smack; package org.jivesoftware.smack;
import org.xmlpull.v1.*; import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.xmlpull.mxp1.MXParser; import org.xmlpull.mxp1.MXParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.util.*; import java.util.*;
import java.util.List;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.util.*;
import org.jivesoftware.smack.provider.*;
/** /**
* Listens for XML traffic from the XMPP server and parses it into packet objects. * Listens for XML traffic from the XMPP server and parses it into packet objects.
@ -97,8 +96,7 @@ class PacketReader {
* @return a new packet collector. * @return a new packet collector.
*/ */
public PacketCollector createPacketCollector(PacketFilter packetFilter) { public PacketCollector createPacketCollector(PacketFilter packetFilter) {
PacketCollector packetCollector = new PacketCollector(this, packetFilter); return new PacketCollector(this, packetFilter);
return packetCollector;
} }
/** /**
@ -158,7 +156,8 @@ class PacketReader {
if (waitTime <= 0) { if (waitTime <= 0) {
break; break;
} }
connectionIDLock.wait(waitTime); // Wait 3 times the standard time since TLS may take a while
connectionIDLock.wait(waitTime * 3);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
waitTime -= now - start; waitTime -= now - start;
start = now; start = now;
@ -217,6 +216,15 @@ class PacketReader {
} }
} }
/**
* Resets the parser using the latest connection's reader. Reseting the parser is necessary
* when the plain connection has been secured or when a new opening stream element is going
* to be sent by the server.
*/
private void resetParser() throws XmlPullParserException {
parser.setInput(connection.reader);
}
/** /**
* Process listeners. * Process listeners.
*/ */
@ -274,19 +282,51 @@ class PacketReader {
// Get the connection id. // Get the connection id.
for (int i=0; i<parser.getAttributeCount(); i++) { for (int i=0; i<parser.getAttributeCount(); i++) {
if (parser.getAttributeName(i).equals("id")) { if (parser.getAttributeName(i).equals("id")) {
// Save the connectionID and notify that we've gotten it. if (("1.0".equals(parser.getAttributeValue("", "version")) &&
synchronized(connectionIDLock) { connection.isUsingTLS()) || (!"1.0".equals(
connectionID = parser.getAttributeValue(i); parser.getAttributeValue("", "version")))) {
connectionIDLock.notifyAll(); // Save the connectionID and notify that we've gotten it.
// Only notify if TLS has been secured or if the server
// does not support TLS
synchronized(connectionIDLock) {
connectionID = parser.getAttributeValue(i);
connectionIDLock.notifyAll();
}
} }
} }
else if (parser.getAttributeName(i).equals("from")) { else if (parser.getAttributeName(i).equals("from")) {
// Use the server name that the server says that it is. // Use the server name that the server says that it is.
connection.host = parser.getAttributeValue(i); connection.serviceName = parser.getAttributeValue(i);
} }
} }
} }
} }
else if (parser.getName().equals("features")) {
parseFeatures(parser);
}
else if (parser.getName().equals("proceed")) {
// Secure the connection by negotiating TLS
connection.proceedTLSReceived();
// Reset the state of the parser since a new stream element is going
// to be sent by the server
resetParser();
}
else if (parser.getName().equals("failure")) {
// TLS negotiation has failed so close the connection.
throw new Exception("TLS negotiation has failed");
}
else if (parser.getName().equals("challenge")) {
// The server is challenging the SASL authentication made by the client
connection.getSASLAuthentication().challengeReceived(parser.nextText());
}
else if (parser.getName().equals("success")) {
// The SASL authentication with the server was successful. The next step
// will be to bind the resource
connection.getSASLAuthentication().authenticated();
// Reset the state of the parser since a new stream element is going
// to be sent by the server
resetParser();
}
} }
else if (eventType == XmlPullParser.END_TAG) { else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals("stream")) { if (parser.getName().equals("stream")) {
@ -338,6 +378,68 @@ class PacketReader {
} }
} }
private void parseFeatures(XmlPullParser parser) throws Exception {
boolean done = false;
while (!done) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals("starttls")) {
// Confirm the server that we want to use TLS
connection.startTLSReceived();
}
else if (parser.getName().equals("mechanisms") && connection.isUsingTLS()) {
// The server is reporting available SASL mechanism. Store this information
// which will be used later while logging (i.e. authenticating) into
// the server
connection.getSASLAuthentication()
.setAvailableSASLMethods(parseMechanisms(parser));
}
else if (parser.getName().equals("bind")) {
// The server requires the client to bind a resource to the stream
connection.getSASLAuthentication().bindingRequired();
}
else if (parser.getName().equals("session")) {
// The server supports sessions
connection.getSASLAuthentication().sessionsSupported();
}
}
else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals("features")) {
done = true;
}
}
}
}
/**
* Returns a collection of Stings with the mechanisms included in the mechanisms stanza.
*
* @param parser the XML parser, positioned at the start of an IQ packet.
* @return a collection of Stings with the mechanisms included in the mechanisms stanza.
* @throws Exception if an exception occurs while parsing the stanza.
*/
private Collection parseMechanisms(XmlPullParser parser) throws Exception {
List mechanisms = new ArrayList();
boolean done = false;
while (!done) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG) {
String elementName = parser.getName();
if (elementName.equals("mechanism")) {
mechanisms.add(parser.nextText());
}
}
else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals("mechanisms")) {
done = true;
}
}
}
return mechanisms;
}
/** /**
* Parses an IQ packet. * Parses an IQ packet.
* *

View file

@ -154,6 +154,10 @@ class PacketWriter {
listenerThread.start(); listenerThread.start();
} }
void setWriter(Writer writer) {
this.writer = writer;
}
/** /**
* Shuts down the packet writer. Once this method has been called, no further * Shuts down the packet writer. Once this method has been called, no further
* packets will be written to the server. * packets will be written to the server.
@ -187,14 +191,7 @@ class PacketWriter {
private void writePackets() { private void writePackets() {
try { try {
// Open the stream. // Open the stream.
StringBuffer stream = new StringBuffer(); openStream();
stream.append("<stream:stream");
stream.append(" to=\"" + connection.getHost() + "\"");
stream.append(" xmlns=\"jabber:client\"");
stream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\">");
writer.write(stream.toString());
writer.flush();
stream = null;
// Write out packets from the queue. // Write out packets from the queue.
while (!done) { while (!done) {
Packet packet = nextPacket(); Packet packet = nextPacket();
@ -273,6 +270,24 @@ class PacketWriter {
} }
} }
/**
* Sends to the server a new stream element. This operation may be requested several times
* so we need to encapsulate the logic in one place. This message will be sent while doing
* TLS, SASL and resource binding.
*
* @throws IOException If an error occurs while sending the stanza to the server.
*/
void openStream() throws IOException {
StringBuffer stream = new StringBuffer();
stream.append("<stream:stream");
stream.append(" to=\"").append(connection.serviceName).append("\"");
stream.append(" xmlns=\"jabber:client\"");
stream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\"");
stream.append(" version=\"1.0\">");
writer.write(stream.toString());
writer.flush();
}
/** /**
* A wrapper class to associate a packet filter with a listener. * A wrapper class to associate a packet filter with a listener.
*/ */
@ -282,7 +297,7 @@ class PacketWriter {
private PacketFilter packetFilter; private PacketFilter packetFilter;
public ListenerWrapper(PacketListener packetListener, public ListenerWrapper(PacketListener packetListener,
PacketFilter packetFilter) PacketFilter packetFilter)
{ {
this.packetListener = packetListener; this.packetListener = packetListener;
this.packetFilter = packetFilter; this.packetFilter = packetFilter;