From 8054a813ea973b69fa655ce0cdfb516db58e4295 Mon Sep 17 00:00:00 2001 From: Manjeet Dahiya Date: Sun, 18 Oct 2009 22:54:04 +0000 Subject: XEP-0078: Non-SASL Authentication Implementation --- source/QXmppClient.cpp | 6 ++ source/QXmppConfiguration.cpp | 32 +++++++++- source/QXmppConfiguration.h | 7 +++ source/QXmppConstants.cpp | 3 +- source/QXmppConstants.h | 2 + source/QXmppNonSASLAuth.cpp | 71 +++++++++++++++++++++ source/QXmppNonSASLAuth.h | 35 +++++++++++ source/QXmppStream.cpp | 142 +++++++++++++++++++++++++++++------------- source/QXmppStream.h | 3 + source/source.pro | 6 +- 10 files changed, 261 insertions(+), 46 deletions(-) create mode 100644 source/QXmppNonSASLAuth.cpp create mode 100644 source/QXmppNonSASLAuth.h (limited to 'source') 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 + +QXmppNonSASLAuthTypesRequestIq::QXmppNonSASLAuthTypesRequestIq() : QXmppIq(QXmppIq::Get) +{ + +} + +void QXmppNonSASLAuthTypesRequestIq::setUsername( const QString &username ) +{ + m_username = username; +} + +QByteArray QXmppNonSASLAuthTypesRequestIq::toXmlElementFromChild() const +{ + QByteArray resultingXml; + resultingXml += ""; + resultingXml += "" + escapeString(m_username).toUtf8() + ""; + resultingXml += ""; + return resultingXml; +} + +QXmppNonSASLAuthIq::QXmppNonSASLAuthIq() : QXmppIq(QXmppIq::Set), m_useplaintext(false) +{ + +} + +QByteArray QXmppNonSASLAuthIq::toXmlElementFromChild() const +{ + QByteArray resultingXml; + resultingXml += ""; + resultingXml += "" + escapeString(m_username).toUtf8() + ""; + if ( m_useplaintext ) + resultingXml += "" + escapeString(m_password).toUtf8() + ""; + 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 + ""; + } + resultingXml += "" + escapeString(m_resource).toUtf8() + ""; + resultingXml += ""; + 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 #include @@ -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(""); } +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 = ""; 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 -- cgit v1.2.3