diff options
| author | Manjeet Dahiya <manjeetdahiya@gmail.com> | 2009-10-18 22:54:04 +0000 |
|---|---|---|
| committer | Manjeet Dahiya <manjeetdahiya@gmail.com> | 2009-10-18 22:54:04 +0000 |
| commit | 8054a813ea973b69fa655ce0cdfb516db58e4295 (patch) | |
| tree | adaaf6c64f467008130b2126fa121aff20a4d286 /source | |
| parent | d7a8921864d1a622ee1125075139b6693a9011c2 (diff) | |
| download | qxmpp-8054a813ea973b69fa655ce0cdfb516db58e4295.tar.gz | |
XEP-0078: Non-SASL Authentication Implementation
Diffstat (limited to 'source')
| -rw-r--r-- | source/QXmppClient.cpp | 6 | ||||
| -rw-r--r-- | source/QXmppConfiguration.cpp | 32 | ||||
| -rw-r--r-- | source/QXmppConfiguration.h | 7 | ||||
| -rw-r--r-- | source/QXmppConstants.cpp | 3 | ||||
| -rw-r--r-- | source/QXmppConstants.h | 2 | ||||
| -rw-r--r-- | source/QXmppNonSASLAuth.cpp | 71 | ||||
| -rw-r--r-- | source/QXmppNonSASLAuth.h | 35 | ||||
| -rw-r--r-- | source/QXmppStream.cpp | 142 | ||||
| -rw-r--r-- | source/QXmppStream.h | 3 | ||||
| -rw-r--r-- | source/source.pro | 6 |
10 files changed, 261 insertions, 46 deletions
diff --git a/source/QXmppClient.cpp b/source/QXmppClient.cpp index e139476b..5c6f892b 100644 --- a/source/QXmppClient.cpp +++ b/source/QXmppClient.cpp @@ -102,6 +102,12 @@ void QXmppClient::connectToServer(const QXmppConfiguration& config, {
m_config = config;
+ if(!m_config.getAutoReconnectionEnabled())
+ {
+ delete m_reconnectionManager;
+ m_reconnectionManager = 0;
+ }
+
m_clientPrecence = initialPresence;
m_stream->connect();
diff --git a/source/QXmppConfiguration.cpp b/source/QXmppConfiguration.cpp index f62d1d98..20336a93 100644 --- a/source/QXmppConfiguration.cpp +++ b/source/QXmppConfiguration.cpp @@ -29,7 +29,8 @@ QXmppConfiguration::QXmppConfiguration() : m_resource("QXmpp"), m_sendIntialPresence(true),
m_sendRosterRequest(true),
m_port(5222),
- m_keepAlivePingsInterval(100), m_autoReconnectionEnabled(true)
+ m_keepAlivePingsInterval(100), m_autoReconnectionEnabled(true),
+ m_useSASLAuthentication(true)
{
}
@@ -118,3 +119,32 @@ void QXmppConfiguration::setAutoAcceptSubscriptions(bool check) m_autoAcceptSubscriptions = check;
}
+bool QXmppConfiguration::getAutoReconnectionEnabled() const
+{
+ return m_autoReconnectionEnabled;
+}
+
+void QXmppConfiguration::setAutoReconnectionEnabled(bool value)
+{
+ m_autoReconnectionEnabled = value;
+}
+
+/// Returns the type of authentication system specified by the user.
+/// \return true if SASL was specified else false. If the specified
+/// system is not available QXmpp will resort to the other one.
+
+bool QXmppConfiguration::getUseSASLAuthentication() const
+{
+ return m_useSASLAuthentication;
+}
+
+/// Returns the type of authentication system specified by the user.
+/// \param useSASL to hint to use SASL authentication system if available.
+/// false will specify to use NonSASL XEP-0078: Non-SASL Authentication
+/// If the specified one is not availbe, library will use the othe one
+
+void QXmppConfiguration::setUseSASLAuthentication(bool useSASL)
+{
+ m_useSASLAuthentication = useSASL;
+}
+
diff --git a/source/QXmppConfiguration.h b/source/QXmppConfiguration.h index b8db22dc..fad1de79 100644 --- a/source/QXmppConfiguration.h +++ b/source/QXmppConfiguration.h @@ -56,6 +56,9 @@ public: bool getAutoReconnectionEnabled() const;
void setAutoReconnectionEnabled(bool);
+ bool getUseSASLAuthentication() const;
+ void setUseSASLAuthentication(bool);
+
private:
QString m_host;
int m_port;
@@ -74,6 +77,10 @@ private: int m_keepAlivePingsInterval;
// will keep reconnecting if disconnected, default is true
bool m_autoReconnectionEnabled;
+ bool m_useSASLAuthentication; ///< flag to specify what authentication system
+ ///< to be used
+ ///< defualt is true and use SASL
+ ///< false would use NonSASL if available
};
#endif // QXMPPCONFIGURATION_H
diff --git a/source/QXmppConstants.cpp b/source/QXmppConstants.cpp index 2540e7b5..ae6c5e6e 100644 --- a/source/QXmppConstants.cpp +++ b/source/QXmppConstants.cpp @@ -33,4 +33,5 @@ const char* ns_bind = "urn:ietf:params:xml:ns:xmpp-bind"; const char* ns_session = "urn:ietf:params:xml:ns:xmpp-session";
const char* ns_stanza = "urn:ietf:params:xml:ns:xmpp-stanzas";
const char* ns_vcard = "vcard-temp";
-
+const char* ns_auth = "jabber:iq:auth";
+const char* ns_authFeature = "http://jabber.org/features/iq-auth";
diff --git a/source/QXmppConstants.h b/source/QXmppConstants.h index cb580f09..4084a89e 100644 --- a/source/QXmppConstants.h +++ b/source/QXmppConstants.h @@ -34,5 +34,7 @@ extern const char* ns_bind; extern const char* ns_session;
extern const char* ns_stanza;
extern const char* ns_vcard;
+extern const char* ns_auth;
+extern const char* ns_authFeature;
#endif // QXMPPCONSTANTS_H
diff --git a/source/QXmppNonSASLAuth.cpp b/source/QXmppNonSASLAuth.cpp new file mode 100644 index 00000000..883bdc0d --- /dev/null +++ b/source/QXmppNonSASLAuth.cpp @@ -0,0 +1,71 @@ +#include "QXmppNonSASLAuth.h"
+#include "QXmppUtils.h"
+#include <QCryptographicHash>
+
+QXmppNonSASLAuthTypesRequestIq::QXmppNonSASLAuthTypesRequestIq() : QXmppIq(QXmppIq::Get)
+{
+
+}
+
+void QXmppNonSASLAuthTypesRequestIq::setUsername( const QString &username )
+{
+ m_username = username;
+}
+
+QByteArray QXmppNonSASLAuthTypesRequestIq::toXmlElementFromChild() const
+{
+ QByteArray resultingXml;
+ resultingXml += "<query xmlns=\"jabber:iq:auth\">";
+ resultingXml += "<username>" + escapeString(m_username).toUtf8() + "</username>";
+ resultingXml += "</query>";
+ return resultingXml;
+}
+
+QXmppNonSASLAuthIq::QXmppNonSASLAuthIq() : QXmppIq(QXmppIq::Set), m_useplaintext(false)
+{
+
+}
+
+QByteArray QXmppNonSASLAuthIq::toXmlElementFromChild() const
+{
+ QByteArray resultingXml;
+ resultingXml += "<query xmlns=\"jabber:iq:auth\">";
+ resultingXml += "<username>" + escapeString(m_username).toUtf8() + "</username>";
+ if ( m_useplaintext )
+ resultingXml += "<password>" + escapeString(m_password).toUtf8() + "</password>";
+ else
+ {//SHA1(concat(sid, password)).
+ QByteArray textSid = m_sid.toUtf8();
+ QByteArray encodedPassword = m_password.toUtf8();
+ QByteArray digest = QCryptographicHash::hash(textSid + encodedPassword, QCryptographicHash::Sha1 ).toHex();
+ resultingXml += "<digest>" + digest + "</digest>";
+ }
+ resultingXml += "<resource>" + escapeString(m_resource).toUtf8() + "</resource>";
+ resultingXml += "</query>";
+ return resultingXml;
+}
+
+void QXmppNonSASLAuthIq::setUsername( const QString &username )
+{
+ m_username = username;
+}
+
+void QXmppNonSASLAuthIq::setPassword( const QString &password )
+{
+ m_password = password;
+}
+
+void QXmppNonSASLAuthIq::setResource( const QString &resource )
+{
+ m_resource = resource;
+}
+
+void QXmppNonSASLAuthIq::setStreamId( const QString &sid )
+{
+ m_sid = sid;
+}
+
+void QXmppNonSASLAuthIq::setUsePlainText( bool use )
+{
+ m_useplaintext = use;
+}
diff --git a/source/QXmppNonSASLAuth.h b/source/QXmppNonSASLAuth.h new file mode 100644 index 00000000..bf071584 --- /dev/null +++ b/source/QXmppNonSASLAuth.h @@ -0,0 +1,35 @@ +#ifndef QXmppNonSASLAuth_H
+#define QXmppNonSASLAuth_H
+
+#include "QXmppIq.h"
+
+class QXmppNonSASLAuthTypesRequestIq : public QXmppIq
+{
+public:
+ QXmppNonSASLAuthTypesRequestIq();
+ void setUsername( const QString &username );
+ virtual QByteArray toXmlElementFromChild() const;
+private:
+ QString m_username;
+};
+
+class QXmppNonSASLAuthIq : public QXmppIq
+{
+public:
+ QXmppNonSASLAuthIq();
+ virtual QByteArray toXmlElementFromChild() const;
+ void setUsername( const QString &username );
+ void setPassword( const QString &password );
+ void setResource( const QString &resource );
+ void setStreamId( const QString &sid );
+ void setUsePlainText( bool useplaintext );
+
+private:
+ QString m_username;
+ QString m_password;
+ QString m_resource;
+ QString m_sid;
+ bool m_useplaintext;
+};
+
+#endif // QXmppNonSASLAuth_H
diff --git a/source/QXmppStream.cpp b/source/QXmppStream.cpp index d8a091f5..0c66cc4b 100644 --- a/source/QXmppStream.cpp +++ b/source/QXmppStream.cpp @@ -35,6 +35,7 @@ #include "QXmppMessage.h"
#include "QXmppConstants.h"
#include "QXmppVCard.h"
+#include "QXmppNonSASLAuth.h"
#include <QDomDocument>
#include <QStringList>
@@ -179,58 +180,78 @@ void QXmppStream::parser(const QByteArray& data) {
log("SERVER:" + m_dataBuffer);
flushDataBuffer();
- // data has valid elements and is not a start or end stream
+
QDomElement nodeRecv = doc.documentElement().firstChildElement();
+
+ if(nodeRecv.isNull())
+ {
+ QDomElement streamElement = doc.documentElement();
+ if(m_streamId.isEmpty())
+ m_streamId = streamElement.attribute("id");
+ }
+
while(!nodeRecv.isNull())
{
QString ns = nodeRecv.namespaceURI();
- if(ns == ns_stream)
+ if(ns == ns_stream && nodeRecv.tagName() == "features")
{
- QString name = nodeRecv.tagName();
- if(name == "features")
+ bool nonSaslAvailable = nodeRecv.firstChildElement("auth").
+ namespaceURI() == ns_authFeature;
+ bool saslAvailable = nodeRecv.firstChildElement("mechanisms").
+ namespaceURI() == ns_sasl;
+ bool useSasl = getConfiguration().getUseSASLAuthentication();
+
+ if(nodeRecv.firstChildElement("starttls").
+ namespaceURI() == ns_tls &&
+ nodeRecv.firstChildElement("starttls").
+ firstChildElement().tagName() == "required")
{
- QDomElement element = nodeRecv.firstChildElement();
- while(!element.isNull())
+ sendStartTls();
+ return;
+ }
+
+ if((saslAvailable && nonSaslAvailable && !useSasl) ||
+ (!saslAvailable && nonSaslAvailable))
+ {
+ // Non-SASL Authentication
+ QDomElement streamElement = doc.documentElement();
+ QString to = streamElement.attribute("from");
+
+ QXmppNonSASLAuthTypesRequestIq authQuery;
+ authQuery.setTo(to);
+ authQuery.setUsername(getConfiguration().getUser());
+
+ sendPacket(authQuery);
+ }
+ else if(saslAvailable)
+ {
+ // SASL Authentication
+ QDomElement element = nodeRecv.firstChildElement("mechanisms");
+ log(QString("Mechanisms:"));
+ QDomElement subElement = element.firstChildElement();
+ QStringList mechanisms;
+ while(!subElement.isNull())
{
- if(element.namespaceURI() == ns_tls)
+ if(subElement.tagName() == "mechanism")
{
- if(element.tagName() == "starttls" &&
- element.firstChildElement().tagName() ==
- "required")
- {
- sendStartTls();
- return;
- }
+ log(subElement.text());
+ mechanisms << subElement.text();
}
- else if(element.namespaceURI() == ns_sasl &&
- element.tagName() == "mechanisms")
- {
- log(QString("Mechanisms:"));
- QDomElement subElement = element.firstChildElement();
- QStringList mechanisms;
- while(!subElement.isNull())
- {
- if(subElement.tagName() == "mechanism")
- {
- log(subElement.text());
- mechanisms << subElement.text();
- }
- subElement = subElement.nextSiblingElement();
- }
- sendAuthPlain();
- }
- else if(element.namespaceURI() == ns_bind &&
- element.tagName() == "bind")
- {
- sendBindIQ();
- }
- else if(element.namespaceURI() == ns_session &&
- element.tagName() == "session")
- {
- m_sessionAvaliable = true;
- }
- element = element.nextSiblingElement();
+ subElement = subElement.nextSiblingElement();
}
+ sendAuthPlain();
+ }
+
+ if(nodeRecv.firstChildElement("bind").
+ namespaceURI() == ns_bind)
+ {
+ sendBindIQ();
+ }
+
+ if(nodeRecv.firstChildElement("session").
+ namespaceURI() == ns_session)
+ {
+ m_sessionAvaliable = true;
}
}
else if(ns == ns_tls)
@@ -252,6 +273,7 @@ void QXmppStream::parser(const QByteArray& data) }
else if(ns == ns_client)
{
+
if(nodeRecv.tagName() == "iq")
{
QDomElement element = nodeRecv.firstChildElement();
@@ -262,10 +284,12 @@ void QXmppStream::parser(const QByteArray& data) if(type.isEmpty())
qWarning("QXmppStream: iq type can't be empty");
QXmppIq iqPacket; // to emit
+
QDomElement elemen = nodeRecv.firstChildElement("error");
QXmppStanza::Error error = parseStanzaError(elemen);
+
if(id == m_sessionId)
{
// get back add configuration whether to send
@@ -335,6 +359,28 @@ void QXmppStream::parser(const QByteArray& data) emit vCardIqReceived(vcardIq);
iqPacket = vcardIq;
}
+ else if(id == m_nonSASLAuthId && type == "result")
+ {
+ // successful Non-SASL Authentication
+ log(QString("Authenticated (Non-SASL)"));
+
+ emit xmppConnected();
+
+ sendRosterRequest();
+ sendInitialPresence();
+ }
+ else if(nodeRecv.firstChildElement("query").
+ namespaceURI() == ns_auth)
+ {
+ if(type == "result")
+ {
+ bool plainText = false;
+ if ( nodeRecv.firstChildElement("query").
+ firstChildElement("digest").isNull() )
+ plainText = true;
+ sendNonSASLAuth(plainText);
+ }
+ }
else // didn't understant the iq...reply with error
{
if(type != "result") // but not incase of result iqs
@@ -458,6 +504,18 @@ void QXmppStream::sendStartTls() sendToServer("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
}
+void QXmppStream::sendNonSASLAuth(bool plainText)
+{
+ QXmppNonSASLAuthIq authQuery;
+ authQuery.setUsername(getConfiguration().getUser());
+ authQuery.setPassword(getConfiguration().getPasswd());
+ authQuery.setResource(getConfiguration().getResource());
+ authQuery.setStreamId(m_streamId);
+ authQuery.setUsePlainText(plainText);
+ m_nonSASLAuthId = authQuery.getId();
+ sendPacket(authQuery);
+}
+
void QXmppStream::sendAuthPlain()
{
QByteArray data = "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>";
diff --git a/source/QXmppStream.h b/source/QXmppStream.h index 132fd40b..6ba95d5d 100644 --- a/source/QXmppStream.h +++ b/source/QXmppStream.h @@ -101,6 +101,8 @@ private: QSslSocket m_socket;
bool m_sessionAvaliable;
QAbstractSocket::SocketError m_socketError;
+ QString m_streamId;
+ QString m_nonSASLAuthId;
// m_xmppStreamError;
// m_xmppStanzaError;
@@ -112,6 +114,7 @@ private: void sendStartStream();
void sendEndStream();
void sendStartTls();
+ void sendNonSASLAuth(bool);
void sendAuthPlain();
void sendBindIQ();
void sendSessionIQ();
diff --git a/source/source.pro b/source/source.pro index 49a65344..cca279bf 100644 --- a/source/source.pro +++ b/source/source.pro @@ -24,7 +24,8 @@ HEADERS += QXmppUtils.h \ QXmppLogger.h \
QXmppReconnectionManager.h \
QXmppVCardManager.h \
- QXmppVCard.h
+ QXmppVCard.h \
+ QXmppNonSASLAuth.h
# Source files
SOURCES += QXmppUtils.cpp \
@@ -44,4 +45,5 @@ SOURCES += QXmppUtils.cpp \ QXmppLogger.cpp \
QXmppReconnectionManager.cpp \
QXmppVCardManager.cpp \
- QXmppVCard.cpp
+ QXmppVCard.cpp \
+ QXmppNonSASLAuth.cpp
|
