mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-12-23 21:17:58 +01: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:
parent
59e393e2ef
commit
ad6be5887c
2 changed files with 142 additions and 25 deletions
|
@ -20,17 +20,16 @@
|
|||
|
||||
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.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
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.
|
||||
|
@ -97,8 +96,7 @@ class PacketReader {
|
|||
* @return a new packet collector.
|
||||
*/
|
||||
public PacketCollector createPacketCollector(PacketFilter packetFilter) {
|
||||
PacketCollector packetCollector = new PacketCollector(this, packetFilter);
|
||||
return packetCollector;
|
||||
return new PacketCollector(this, packetFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -158,7 +156,8 @@ class PacketReader {
|
|||
if (waitTime <= 0) {
|
||||
break;
|
||||
}
|
||||
connectionIDLock.wait(waitTime);
|
||||
// Wait 3 times the standard time since TLS may take a while
|
||||
connectionIDLock.wait(waitTime * 3);
|
||||
long now = System.currentTimeMillis();
|
||||
waitTime -= now - start;
|
||||
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.
|
||||
*/
|
||||
|
@ -274,19 +282,51 @@ class PacketReader {
|
|||
// Get the connection id.
|
||||
for (int i=0; i<parser.getAttributeCount(); i++) {
|
||||
if (parser.getAttributeName(i).equals("id")) {
|
||||
// Save the connectionID and notify that we've gotten it.
|
||||
synchronized(connectionIDLock) {
|
||||
connectionID = parser.getAttributeValue(i);
|
||||
connectionIDLock.notifyAll();
|
||||
if (("1.0".equals(parser.getAttributeValue("", "version")) &&
|
||||
connection.isUsingTLS()) || (!"1.0".equals(
|
||||
parser.getAttributeValue("", "version")))) {
|
||||
// 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")) {
|
||||
// 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) {
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -154,6 +154,10 @@ class PacketWriter {
|
|||
listenerThread.start();
|
||||
}
|
||||
|
||||
void setWriter(Writer writer) {
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the packet writer. Once this method has been called, no further
|
||||
* packets will be written to the server.
|
||||
|
@ -187,14 +191,7 @@ class PacketWriter {
|
|||
private void writePackets() {
|
||||
try {
|
||||
// Open the stream.
|
||||
StringBuffer stream = new StringBuffer();
|
||||
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;
|
||||
openStream();
|
||||
// Write out packets from the queue.
|
||||
while (!done) {
|
||||
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.
|
||||
*/
|
||||
|
@ -282,7 +297,7 @@ class PacketWriter {
|
|||
private PacketFilter packetFilter;
|
||||
|
||||
public ListenerWrapper(PacketListener packetListener,
|
||||
PacketFilter packetFilter)
|
||||
PacketFilter packetFilter)
|
||||
{
|
||||
this.packetListener = packetListener;
|
||||
this.packetFilter = packetFilter;
|
||||
|
|
Loading…
Reference in a new issue