From 51eef84fd4104f19228ebd85fce89658b64464a2 Mon Sep 17 00:00:00 2001 From: Jeremy Lainé Date: Fri, 20 Jul 2012 17:37:38 +0200 Subject: make SASL code fully private --- src/base/QXmppSasl.cpp | 742 ++++++++++++++++++++++++++++++++++++++++++++ src/base/QXmppSaslAuth.cpp | 743 --------------------------------------------- src/base/QXmppSaslAuth.h | 102 ------- src/base/QXmppSaslAuth_p.h | 227 -------------- src/base/QXmppSasl_p.h | 300 ++++++++++++++++++ src/base/base.pri | 3 +- 6 files changed, 1043 insertions(+), 1074 deletions(-) create mode 100644 src/base/QXmppSasl.cpp delete mode 100644 src/base/QXmppSaslAuth.cpp delete mode 100644 src/base/QXmppSaslAuth.h delete mode 100644 src/base/QXmppSaslAuth_p.h create mode 100644 src/base/QXmppSasl_p.h (limited to 'src/base') diff --git a/src/base/QXmppSasl.cpp b/src/base/QXmppSasl.cpp new file mode 100644 index 00000000..d37644ca --- /dev/null +++ b/src/base/QXmppSasl.cpp @@ -0,0 +1,742 @@ +/* + * Copyright (C) 2008-2012 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#include + +#include +#include +#include +#include + +#include "QXmppSasl_p.h" +#include "QXmppUtils.h" + +const char *ns_xmpp_sasl = "urn:ietf:params:xml:ns:xmpp-sasl"; + +static QByteArray forcedNonce; + +// Calculate digest response for use with XMPP/SASL. + +static QByteArray calculateDigest(const QByteArray &method, const QByteArray &digestUri, const QByteArray &secret, const QByteArray &nonce, const QByteArray &cnonce, const QByteArray &nc) +{ + const QByteArray A1 = secret + ':' + nonce + ':' + cnonce; + const QByteArray A2 = method + ':' + digestUri; + + QByteArray HA1 = QCryptographicHash::hash(A1, QCryptographicHash::Md5).toHex(); + QByteArray HA2 = QCryptographicHash::hash(A2, QCryptographicHash::Md5).toHex(); + const QByteArray KD = HA1 + ':' + nonce + ':' + nc + ':' + cnonce + ":auth:" + HA2; + return QCryptographicHash::hash(KD, QCryptographicHash::Md5).toHex(); +} + +static QByteArray generateNonce() +{ + if (!forcedNonce.isEmpty()) + return forcedNonce; + + QByteArray nonce = QXmppUtils::generateRandomBytes(32); + + // The random data can the '=' char is not valid as it is a delimiter, + // so to be safe, base64 the nonce + return nonce.toBase64(); +} + +QXmppSaslAuth::QXmppSaslAuth(const QString &mechanism, const QByteArray &value) + : QXmppSaslStanza("auth", value) + , m_mechanism(mechanism) +{ +} + +QString QXmppSaslAuth::mechanism() const +{ + return m_mechanism; +} + +void QXmppSaslAuth::setMechanism(const QString &mechanism) +{ + m_mechanism = mechanism; +} + +void QXmppSaslAuth::parse(const QDomElement &element) +{ + m_mechanism = element.attribute("mechanism"); + setValue(QByteArray::fromBase64(element.text().toAscii())); +} + +void QXmppSaslAuth::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("auth"); + writer->writeAttribute("xmlns", ns_xmpp_sasl); + writer->writeAttribute("mechanism", m_mechanism); + if (!value().isEmpty()) + writer->writeCharacters(value().toBase64()); + writer->writeEndElement(); +} + +QXmppSaslChallenge::QXmppSaslChallenge(const QByteArray &value) + : QXmppSaslStanza("challenge", value) +{ +} + +QXmppSaslFailure::QXmppSaslFailure(const QString &condition) + : QXmppSaslStanza("failure") + , m_condition(condition) +{ +} + +QString QXmppSaslFailure::condition() const +{ + return m_condition; +} + +void QXmppSaslFailure::setCondition(const QString &condition) +{ + m_condition = condition; +} + +void QXmppSaslFailure::parse(const QDomElement &element) +{ + m_condition = element.firstChildElement().tagName(); +} + +void QXmppSaslFailure::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("failure"); + writer->writeAttribute("xmlns", ns_xmpp_sasl); + if (!m_condition.isEmpty()) + writer->writeEmptyElement(m_condition); + writer->writeEndElement(); +} + +QXmppSaslResponse::QXmppSaslResponse(const QByteArray &value) + : QXmppSaslStanza("response", value) +{ +} + +QXmppSaslSuccess::QXmppSaslSuccess() + : QXmppSaslStanza("success") +{ +} + +QXmppSaslStanza::QXmppSaslStanza(const QString &type, const QByteArray &value) + : m_type(type) + , m_value(value) +{ +} + +QByteArray QXmppSaslStanza::value() const +{ + return m_value; +} + +void QXmppSaslStanza::setValue(const QByteArray &value) +{ + m_value = value; +} + + +void QXmppSaslStanza::parse(const QDomElement &element) +{ + m_type = element.nodeName(); + m_value = QByteArray::fromBase64(element.text().toAscii()); +} + +void QXmppSaslStanza::toXml(QXmlStreamWriter *writer) const +{ + if (!m_type.isEmpty()) { + writer->writeStartElement(m_type); + writer->writeAttribute("xmlns", ns_xmpp_sasl); + if (!m_value.isEmpty()) + writer->writeCharacters(m_value.toBase64()); + writer->writeEndElement(); + } +} + +class QXmppSaslClientPrivate +{ +public: + QString host; + QString serviceType; + QString username; + QString password; +}; + +QXmppSaslClient::QXmppSaslClient(QObject *parent) + : QXmppLoggable(parent) + , d(new QXmppSaslClientPrivate) +{ +} + +QXmppSaslClient::~QXmppSaslClient() +{ + delete d; +} + +/// Returns a list of supported mechanisms. + +QStringList QXmppSaslClient::availableMechanisms() +{ + return QStringList() << "PLAIN" << "DIGEST-MD5" << "ANONYMOUS" << "X-FACEBOOK-PLATFORM"; +} + +/// Creates an SASL client for the given mechanism. + +QXmppSaslClient* QXmppSaslClient::create(const QString &mechanism, QObject *parent) +{ + if (mechanism == "PLAIN") { + return new QXmppSaslClientPlain(parent); + } else if (mechanism == "DIGEST-MD5") { + return new QXmppSaslClientDigestMd5(parent); + } else if (mechanism == "ANONYMOUS") { + return new QXmppSaslClientAnonymous(parent); + } else if (mechanism == "X-FACEBOOK-PLATFORM") { + return new QXmppSaslClientFacebook(parent); + } else { + return 0; + } +} + +/// Returns the host. + +QString QXmppSaslClient::host() const +{ + return d->host; +} + +/// Sets the host. + +void QXmppSaslClient::setHost(const QString &host) +{ + d->host = host; +} + +/// Returns the service type, e.g. "xmpp". + +QString QXmppSaslClient::serviceType() const +{ + return d->serviceType; +} + +/// Sets the service type, e.g. "xmpp". + +void QXmppSaslClient::setServiceType(const QString &serviceType) +{ + d->serviceType = serviceType; +} + +/// Returns the username. + +QString QXmppSaslClient::username() const +{ + return d->username; +} + +/// Sets the username. + +void QXmppSaslClient::setUsername(const QString &username) +{ + d->username = username; +} + +/// Returns the password. + +QString QXmppSaslClient::password() const +{ + return d->password; +} + +/// Sets the password. + +void QXmppSaslClient::setPassword(const QString &password) +{ + d->password = password; +} + +QXmppSaslClientAnonymous::QXmppSaslClientAnonymous(QObject *parent) + : QXmppSaslClient(parent) + , m_step(0) +{ +} + +QString QXmppSaslClientAnonymous::mechanism() const +{ + return "ANONYMOUS"; +} + +bool QXmppSaslClientAnonymous::respond(const QByteArray &challenge, QByteArray &response) +{ + Q_UNUSED(challenge); + if (m_step == 0) { + response = QByteArray(); + m_step++; + return true; + } else { + warning("QXmppSaslClientAnonymous : Invalid step"); + return false; + } +} + +QXmppSaslClientDigestMd5::QXmppSaslClientDigestMd5(QObject *parent) + : QXmppSaslClient(parent) + , m_nc("00000001") + , m_step(0) +{ + m_cnonce = generateNonce(); +} + +QString QXmppSaslClientDigestMd5::mechanism() const +{ + return "DIGEST-MD5"; +} + +bool QXmppSaslClientDigestMd5::respond(const QByteArray &challenge, QByteArray &response) +{ + Q_UNUSED(challenge); + const QByteArray digestUri = QString("%1/%2").arg(serviceType(), host()).toUtf8(); + + if (m_step == 0) { + response = QByteArray(); + m_step++; + return true; + } else if (m_step == 1) { + const QMap input = QXmppSaslDigestMd5::parseMessage(challenge); + + if (!input.contains("nonce")) { + warning("QXmppSaslClientDigestMd5 : Invalid input on step 1"); + return false; + } + + // determine realm + const QByteArray realm = input.value("realm"); + + // determine quality of protection + const QList qops = input.value("qop", "auth").split(','); + if (!qops.contains("auth")) { + warning("QXmppSaslClientDigestMd5 : Invalid quality of protection"); + return false; + } + + m_nonce = input.value("nonce"); + m_secret = QCryptographicHash::hash( + username().toUtf8() + ":" + realm + ":" + password().toUtf8(), + QCryptographicHash::Md5); + + // Build response + QMap output; + output["username"] = username().toUtf8(); + if (!realm.isEmpty()) + output["realm"] = realm; + output["nonce"] = m_nonce; + output["qop"] = "auth"; + output["cnonce"] = m_cnonce; + output["nc"] = m_nc; + output["digest-uri"] = digestUri; + output["response"] = calculateDigest("AUTHENTICATE", digestUri, m_secret, m_nonce, m_cnonce, m_nc); + output["charset"] = "utf-8"; + + response = QXmppSaslDigestMd5::serializeMessage(output); + m_step++; + return true; + } else if (m_step == 2) { + const QMap input = QXmppSaslDigestMd5::parseMessage(challenge); + + // check new challenge + if (input.value("rspauth") != calculateDigest(QByteArray(), digestUri, m_secret, m_nonce, m_cnonce, m_nc)) { + warning("QXmppSaslClientDigestMd5 : Invalid challenge on step 2"); + return false; + } + + response = QByteArray(); + m_step++; + return true; + } else { + warning("QXmppSaslClientDigestMd5 : Invalid step"); + return false; + } +} + +QXmppSaslClientFacebook::QXmppSaslClientFacebook(QObject *parent) + : QXmppSaslClient(parent) + , m_step(0) +{ +} + +QString QXmppSaslClientFacebook::mechanism() const +{ + return "X-FACEBOOK-PLATFORM"; +} + +bool QXmppSaslClientFacebook::respond(const QByteArray &challenge, QByteArray &response) +{ + if (m_step == 0) { + // no initial response + response = QByteArray(); + m_step++; + return true; + } else if (m_step == 1) { + // parse request + QUrl requestUrl; + requestUrl.setEncodedQuery(challenge); + if (!requestUrl.hasQueryItem("method") || !requestUrl.hasQueryItem("nonce")) { + warning("QXmppSaslClientFacebook : Invalid challenge, nonce or method missing"); + return false; + } + + // build response + QUrl responseUrl; + responseUrl.addQueryItem("access_token", username()); + responseUrl.addQueryItem("api_key", password()); + responseUrl.addQueryItem("call_id", 0); + responseUrl.addQueryItem("method", requestUrl.queryItemValue("method")); + responseUrl.addQueryItem("nonce", requestUrl.queryItemValue("nonce")); + responseUrl.addQueryItem("v", "1.0"); + + response = responseUrl.encodedQuery(); + m_step++; + return true; + } else { + warning("QXmppSaslClientFacebook : Invalid step"); + return false; + } +} + +QXmppSaslClientPlain::QXmppSaslClientPlain(QObject *parent) + : QXmppSaslClient(parent) + , m_step(0) +{ +} + +QString QXmppSaslClientPlain::mechanism() const +{ + return "PLAIN"; +} + +bool QXmppSaslClientPlain::respond(const QByteArray &challenge, QByteArray &response) +{ + Q_UNUSED(challenge); + if (m_step == 0) { + response = QString('\0' + username() + '\0' + password()).toUtf8(); + m_step++; + return true; + } else { + warning("QXmppSaslClientPlain : Invalid step"); + return false; + } +} + +class QXmppSaslServerPrivate +{ +public: + QString username; + QString password; + QByteArray passwordDigest; + QString realm; +}; + +QXmppSaslServer::QXmppSaslServer(QObject *parent) + : QXmppLoggable(parent) + , d(new QXmppSaslServerPrivate) +{ +} + +QXmppSaslServer::~QXmppSaslServer() +{ + delete d; +} + +/// Creates an SASL server for the given mechanism. + +QXmppSaslServer* QXmppSaslServer::create(const QString &mechanism, QObject *parent) +{ + if (mechanism == "PLAIN") { + return new QXmppSaslServerPlain(parent); + } else if (mechanism == "DIGEST-MD5") { + return new QXmppSaslServerDigestMd5(parent); + } else if (mechanism == "ANONYMOUS") { + return new QXmppSaslServerAnonymous(parent); + } else { + return 0; + } +} + +/// Returns the username. + +QString QXmppSaslServer::username() const +{ + return d->username; +} + +/// Sets the username. + +void QXmppSaslServer::setUsername(const QString &username) +{ + d->username = username; +} + +/// Returns the password. + +QString QXmppSaslServer::password() const +{ + return d->password; +} + +/// Sets the password. + +void QXmppSaslServer::setPassword(const QString &password) +{ + d->password = password; +} + +/// Returns the password digest. + +QByteArray QXmppSaslServer::passwordDigest() const +{ + return d->passwordDigest; +} + +/// Sets the password digest. + +void QXmppSaslServer::setPasswordDigest(const QByteArray &digest) +{ + d->passwordDigest = digest; +} + +/// Returns the realm. + +QString QXmppSaslServer::realm() const +{ + return d->realm; +} + +/// Sets the realm. + +void QXmppSaslServer::setRealm(const QString &realm) +{ + d->realm = realm; +} + +QXmppSaslServerAnonymous::QXmppSaslServerAnonymous(QObject *parent) + : QXmppSaslServer(parent) + , m_step(0) +{ +} + +QString QXmppSaslServerAnonymous::mechanism() const +{ + return "ANONYMOUS"; +} + +QXmppSaslServer::Response QXmppSaslServerAnonymous::respond(const QByteArray &request, QByteArray &response) +{ + Q_UNUSED(request); + if (m_step == 0) { + m_step++; + response = QByteArray(); + return Succeeded; + } else { + warning("QXmppSaslServerAnonymous : Invalid step"); + return Failed; + } +} + +QXmppSaslServerDigestMd5::QXmppSaslServerDigestMd5(QObject *parent) + : QXmppSaslServer(parent) + , m_step(0) +{ + m_nonce = generateNonce(); +} + +QString QXmppSaslServerDigestMd5::mechanism() const +{ + return "DIGEST-MD5"; +} + +QXmppSaslServer::Response QXmppSaslServerDigestMd5::respond(const QByteArray &request, QByteArray &response) +{ + if (m_step == 0) { + QMap output; + output["nonce"] = m_nonce; + if (!realm().isEmpty()) + output["realm"] = realm().toUtf8(); + output["qop"] = "auth"; + output["charset"] = "utf-8"; + output["algorithm"] = "md5-sess"; + + m_step++; + response = QXmppSaslDigestMd5::serializeMessage(output); + return Challenge; + } else if (m_step == 1) { + const QMap input = QXmppSaslDigestMd5::parseMessage(request); + const QByteArray realm = input.value("realm"); + const QByteArray digestUri = input.value("digest-uri"); + + if (input.value("qop") != "auth") { + warning("QXmppSaslServerDigestMd5 : Invalid quality of protection"); + return Failed; + } + + setUsername(QString::fromUtf8(input.value("username"))); + if (password().isEmpty() && passwordDigest().isEmpty()) + return InputNeeded; + + m_nc = input.value("nc"); + m_cnonce = input.value("cnonce"); + if (!password().isEmpty()) { + m_secret = QCryptographicHash::hash( + username().toUtf8() + ":" + realm + ":" + password().toUtf8(), + QCryptographicHash::Md5); + } else { + m_secret = passwordDigest(); + } + + if (input.value("response") != calculateDigest("AUTHENTICATE", digestUri, m_secret, m_nonce, m_cnonce, m_nc)) + return Failed; + + QMap output; + output["rspauth"] = calculateDigest(QByteArray(), digestUri, m_secret, m_nonce, m_cnonce, m_nc); + + m_step++; + response = QXmppSaslDigestMd5::serializeMessage(output); + return Challenge; + } else if (m_step == 2) { + m_step++; + response = QByteArray(); + return Succeeded; + } else { + warning("QXmppSaslServerDigestMd5 : Invalid step"); + return Failed; + } +} + +QXmppSaslServerPlain::QXmppSaslServerPlain(QObject *parent) + : QXmppSaslServer(parent) + , m_step(0) +{ +} + +QString QXmppSaslServerPlain::mechanism() const +{ + return "PLAIN"; +} + +QXmppSaslServer::Response QXmppSaslServerPlain::respond(const QByteArray &request, QByteArray &response) +{ + if (m_step == 0) { + QList auth = request.split('\0'); + if (auth.size() != 3) { + warning("QXmppSaslServerPlain : Invalid input"); + return Failed; + } + setUsername(QString::fromUtf8(auth[1])); + setPassword(QString::fromUtf8(auth[2])); + + m_step++; + response = QByteArray(); + return InputNeeded; + } else { + warning("QXmppSaslServerPlain : Invalid step"); + return Failed; + } +} + +void QXmppSaslDigestMd5::setNonce(const QByteArray &nonce) +{ + forcedNonce = nonce; +} + +QMap QXmppSaslDigestMd5::parseMessage(const QByteArray &ba) +{ + QMap map; + int startIndex = 0; + int pos = 0; + while ((pos = ba.indexOf("=", startIndex)) >= 0) + { + // key get name and skip equals + const QByteArray key = ba.mid(startIndex, pos - startIndex).trimmed(); + pos++; + + // check whether string is quoted + if (ba.at(pos) == '"') + { + // skip opening quote + pos++; + int endPos = ba.indexOf('"', pos); + // skip quoted quotes + while (endPos >= 0 && ba.at(endPos - 1) == '\\') + endPos = ba.indexOf('"', endPos + 1); + if (endPos < 0) + { + qWarning("Unfinished quoted string"); + return map; + } + // unquote + QByteArray value = ba.mid(pos, endPos - pos); + value.replace("\\\"", "\""); + value.replace("\\\\", "\\"); + map[key] = value; + // skip closing quote and comma + startIndex = endPos + 2; + } else { + // non-quoted string + int endPos = ba.indexOf(',', pos); + if (endPos < 0) + endPos = ba.size(); + map[key] = ba.mid(pos, endPos - pos); + // skip comma + startIndex = endPos + 1; + } + } + return map; +} + +QByteArray QXmppSaslDigestMd5::serializeMessage(const QMap &map) +{ + QByteArray ba; + foreach (const QByteArray &key, map.keys()) + { + if (!ba.isEmpty()) + ba.append(','); + ba.append(key + "="); + QByteArray value = map[key]; + const char *separators = "()<>@,;:\\\"/[]?={} \t"; + bool quote = false; + for (const char *c = separators; *c; c++) + { + if (value.contains(*c)) + { + quote = true; + break; + } + } + if (quote) + { + value.replace("\\", "\\\\"); + value.replace("\"", "\\\""); + ba.append("\"" + value + "\""); + } + else + ba.append(value); + } + return ba; +} + diff --git a/src/base/QXmppSaslAuth.cpp b/src/base/QXmppSaslAuth.cpp deleted file mode 100644 index 1c15ae02..00000000 --- a/src/base/QXmppSaslAuth.cpp +++ /dev/null @@ -1,743 +0,0 @@ -/* - * Copyright (C) 2008-2012 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - */ - -#include - -#include -#include -#include -#include - -#include "QXmppSaslAuth.h" -#include "QXmppSaslAuth_p.h" -#include "QXmppUtils.h" - -const char *ns_xmpp_sasl = "urn:ietf:params:xml:ns:xmpp-sasl"; - -static QByteArray forcedNonce; - -// Calculate digest response for use with XMPP/SASL. - -static QByteArray calculateDigest(const QByteArray &method, const QByteArray &digestUri, const QByteArray &secret, const QByteArray &nonce, const QByteArray &cnonce, const QByteArray &nc) -{ - const QByteArray A1 = secret + ':' + nonce + ':' + cnonce; - const QByteArray A2 = method + ':' + digestUri; - - QByteArray HA1 = QCryptographicHash::hash(A1, QCryptographicHash::Md5).toHex(); - QByteArray HA2 = QCryptographicHash::hash(A2, QCryptographicHash::Md5).toHex(); - const QByteArray KD = HA1 + ':' + nonce + ':' + nc + ':' + cnonce + ":auth:" + HA2; - return QCryptographicHash::hash(KD, QCryptographicHash::Md5).toHex(); -} - -static QByteArray generateNonce() -{ - if (!forcedNonce.isEmpty()) - return forcedNonce; - - QByteArray nonce = QXmppUtils::generateRandomBytes(32); - - // The random data can the '=' char is not valid as it is a delimiter, - // so to be safe, base64 the nonce - return nonce.toBase64(); -} - -QXmppSaslAuth::QXmppSaslAuth(const QString &mechanism, const QByteArray &value) - : QXmppSaslStanza("auth", value) - , m_mechanism(mechanism) -{ -} - -QString QXmppSaslAuth::mechanism() const -{ - return m_mechanism; -} - -void QXmppSaslAuth::setMechanism(const QString &mechanism) -{ - m_mechanism = mechanism; -} - -void QXmppSaslAuth::parse(const QDomElement &element) -{ - m_mechanism = element.attribute("mechanism"); - setValue(QByteArray::fromBase64(element.text().toAscii())); -} - -void QXmppSaslAuth::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("auth"); - writer->writeAttribute("xmlns", ns_xmpp_sasl); - writer->writeAttribute("mechanism", m_mechanism); - if (!value().isEmpty()) - writer->writeCharacters(value().toBase64()); - writer->writeEndElement(); -} - -QXmppSaslChallenge::QXmppSaslChallenge(const QByteArray &value) - : QXmppSaslStanza("challenge", value) -{ -} - -QXmppSaslFailure::QXmppSaslFailure(const QString &condition) - : QXmppSaslStanza("failure") - , m_condition(condition) -{ -} - -QString QXmppSaslFailure::condition() const -{ - return m_condition; -} - -void QXmppSaslFailure::setCondition(const QString &condition) -{ - m_condition = condition; -} - -void QXmppSaslFailure::parse(const QDomElement &element) -{ - m_condition = element.firstChildElement().tagName(); -} - -void QXmppSaslFailure::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("failure"); - writer->writeAttribute("xmlns", ns_xmpp_sasl); - if (!m_condition.isEmpty()) - writer->writeEmptyElement(m_condition); - writer->writeEndElement(); -} - -QXmppSaslResponse::QXmppSaslResponse(const QByteArray &value) - : QXmppSaslStanza("response", value) -{ -} - -QXmppSaslSuccess::QXmppSaslSuccess() - : QXmppSaslStanza("success") -{ -} - -QXmppSaslStanza::QXmppSaslStanza(const QString &type, const QByteArray &value) - : m_type(type) - , m_value(value) -{ -} - -QByteArray QXmppSaslStanza::value() const -{ - return m_value; -} - -void QXmppSaslStanza::setValue(const QByteArray &value) -{ - m_value = value; -} - - -void QXmppSaslStanza::parse(const QDomElement &element) -{ - m_type = element.nodeName(); - m_value = QByteArray::fromBase64(element.text().toAscii()); -} - -void QXmppSaslStanza::toXml(QXmlStreamWriter *writer) const -{ - if (!m_type.isEmpty()) { - writer->writeStartElement(m_type); - writer->writeAttribute("xmlns", ns_xmpp_sasl); - if (!m_value.isEmpty()) - writer->writeCharacters(m_value.toBase64()); - writer->writeEndElement(); - } -} - -class QXmppSaslClientPrivate -{ -public: - QString host; - QString serviceType; - QString username; - QString password; -}; - -QXmppSaslClient::QXmppSaslClient(QObject *parent) - : QXmppLoggable(parent) - , d(new QXmppSaslClientPrivate) -{ -} - -QXmppSaslClient::~QXmppSaslClient() -{ - delete d; -} - -/// Returns a list of supported mechanisms. - -QStringList QXmppSaslClient::availableMechanisms() -{ - return QStringList() << "PLAIN" << "DIGEST-MD5" << "ANONYMOUS" << "X-FACEBOOK-PLATFORM"; -} - -/// Creates an SASL client for the given mechanism. - -QXmppSaslClient* QXmppSaslClient::create(const QString &mechanism, QObject *parent) -{ - if (mechanism == "PLAIN") { - return new QXmppSaslClientPlain(parent); - } else if (mechanism == "DIGEST-MD5") { - return new QXmppSaslClientDigestMd5(parent); - } else if (mechanism == "ANONYMOUS") { - return new QXmppSaslClientAnonymous(parent); - } else if (mechanism == "X-FACEBOOK-PLATFORM") { - return new QXmppSaslClientFacebook(parent); - } else { - return 0; - } -} - -/// Returns the host. - -QString QXmppSaslClient::host() const -{ - return d->host; -} - -/// Sets the host. - -void QXmppSaslClient::setHost(const QString &host) -{ - d->host = host; -} - -/// Returns the service type, e.g. "xmpp". - -QString QXmppSaslClient::serviceType() const -{ - return d->serviceType; -} - -/// Sets the service type, e.g. "xmpp". - -void QXmppSaslClient::setServiceType(const QString &serviceType) -{ - d->serviceType = serviceType; -} - -/// Returns the username. - -QString QXmppSaslClient::username() const -{ - return d->username; -} - -/// Sets the username. - -void QXmppSaslClient::setUsername(const QString &username) -{ - d->username = username; -} - -/// Returns the password. - -QString QXmppSaslClient::password() const -{ - return d->password; -} - -/// Sets the password. - -void QXmppSaslClient::setPassword(const QString &password) -{ - d->password = password; -} - -QXmppSaslClientAnonymous::QXmppSaslClientAnonymous(QObject *parent) - : QXmppSaslClient(parent) - , m_step(0) -{ -} - -QString QXmppSaslClientAnonymous::mechanism() const -{ - return "ANONYMOUS"; -} - -bool QXmppSaslClientAnonymous::respond(const QByteArray &challenge, QByteArray &response) -{ - Q_UNUSED(challenge); - if (m_step == 0) { - response = QByteArray(); - m_step++; - return true; - } else { - warning("QXmppSaslClientAnonymous : Invalid step"); - return false; - } -} - -QXmppSaslClientDigestMd5::QXmppSaslClientDigestMd5(QObject *parent) - : QXmppSaslClient(parent) - , m_nc("00000001") - , m_step(0) -{ - m_cnonce = generateNonce(); -} - -QString QXmppSaslClientDigestMd5::mechanism() const -{ - return "DIGEST-MD5"; -} - -bool QXmppSaslClientDigestMd5::respond(const QByteArray &challenge, QByteArray &response) -{ - Q_UNUSED(challenge); - const QByteArray digestUri = QString("%1/%2").arg(serviceType(), host()).toUtf8(); - - if (m_step == 0) { - response = QByteArray(); - m_step++; - return true; - } else if (m_step == 1) { - const QMap input = QXmppSaslDigestMd5::parseMessage(challenge); - - if (!input.contains("nonce")) { - warning("QXmppSaslClientDigestMd5 : Invalid input on step 1"); - return false; - } - - // determine realm - const QByteArray realm = input.value("realm"); - - // determine quality of protection - const QList qops = input.value("qop", "auth").split(','); - if (!qops.contains("auth")) { - warning("QXmppSaslClientDigestMd5 : Invalid quality of protection"); - return false; - } - - m_nonce = input.value("nonce"); - m_secret = QCryptographicHash::hash( - username().toUtf8() + ":" + realm + ":" + password().toUtf8(), - QCryptographicHash::Md5); - - // Build response - QMap output; - output["username"] = username().toUtf8(); - if (!realm.isEmpty()) - output["realm"] = realm; - output["nonce"] = m_nonce; - output["qop"] = "auth"; - output["cnonce"] = m_cnonce; - output["nc"] = m_nc; - output["digest-uri"] = digestUri; - output["response"] = calculateDigest("AUTHENTICATE", digestUri, m_secret, m_nonce, m_cnonce, m_nc); - output["charset"] = "utf-8"; - - response = QXmppSaslDigestMd5::serializeMessage(output); - m_step++; - return true; - } else if (m_step == 2) { - const QMap input = QXmppSaslDigestMd5::parseMessage(challenge); - - // check new challenge - if (input.value("rspauth") != calculateDigest(QByteArray(), digestUri, m_secret, m_nonce, m_cnonce, m_nc)) { - warning("QXmppSaslClientDigestMd5 : Invalid challenge on step 2"); - return false; - } - - response = QByteArray(); - m_step++; - return true; - } else { - warning("QXmppSaslClientDigestMd5 : Invalid step"); - return false; - } -} - -QXmppSaslClientFacebook::QXmppSaslClientFacebook(QObject *parent) - : QXmppSaslClient(parent) - , m_step(0) -{ -} - -QString QXmppSaslClientFacebook::mechanism() const -{ - return "X-FACEBOOK-PLATFORM"; -} - -bool QXmppSaslClientFacebook::respond(const QByteArray &challenge, QByteArray &response) -{ - if (m_step == 0) { - // no initial response - response = QByteArray(); - m_step++; - return true; - } else if (m_step == 1) { - // parse request - QUrl requestUrl; - requestUrl.setEncodedQuery(challenge); - if (!requestUrl.hasQueryItem("method") || !requestUrl.hasQueryItem("nonce")) { - warning("QXmppSaslClientFacebook : Invalid challenge, nonce or method missing"); - return false; - } - - // build response - QUrl responseUrl; - responseUrl.addQueryItem("access_token", username()); - responseUrl.addQueryItem("api_key", password()); - responseUrl.addQueryItem("call_id", 0); - responseUrl.addQueryItem("method", requestUrl.queryItemValue("method")); - responseUrl.addQueryItem("nonce", requestUrl.queryItemValue("nonce")); - responseUrl.addQueryItem("v", "1.0"); - - response = responseUrl.encodedQuery(); - m_step++; - return true; - } else { - warning("QXmppSaslClientFacebook : Invalid step"); - return false; - } -} - -QXmppSaslClientPlain::QXmppSaslClientPlain(QObject *parent) - : QXmppSaslClient(parent) - , m_step(0) -{ -} - -QString QXmppSaslClientPlain::mechanism() const -{ - return "PLAIN"; -} - -bool QXmppSaslClientPlain::respond(const QByteArray &challenge, QByteArray &response) -{ - Q_UNUSED(challenge); - if (m_step == 0) { - response = QString('\0' + username() + '\0' + password()).toUtf8(); - m_step++; - return true; - } else { - warning("QXmppSaslClientPlain : Invalid step"); - return false; - } -} - -class QXmppSaslServerPrivate -{ -public: - QString username; - QString password; - QByteArray passwordDigest; - QString realm; -}; - -QXmppSaslServer::QXmppSaslServer(QObject *parent) - : QXmppLoggable(parent) - , d(new QXmppSaslServerPrivate) -{ -} - -QXmppSaslServer::~QXmppSaslServer() -{ - delete d; -} - -/// Creates an SASL server for the given mechanism. - -QXmppSaslServer* QXmppSaslServer::create(const QString &mechanism, QObject *parent) -{ - if (mechanism == "PLAIN") { - return new QXmppSaslServerPlain(parent); - } else if (mechanism == "DIGEST-MD5") { - return new QXmppSaslServerDigestMd5(parent); - } else if (mechanism == "ANONYMOUS") { - return new QXmppSaslServerAnonymous(parent); - } else { - return 0; - } -} - -/// Returns the username. - -QString QXmppSaslServer::username() const -{ - return d->username; -} - -/// Sets the username. - -void QXmppSaslServer::setUsername(const QString &username) -{ - d->username = username; -} - -/// Returns the password. - -QString QXmppSaslServer::password() const -{ - return d->password; -} - -/// Sets the password. - -void QXmppSaslServer::setPassword(const QString &password) -{ - d->password = password; -} - -/// Returns the password digest. - -QByteArray QXmppSaslServer::passwordDigest() const -{ - return d->passwordDigest; -} - -/// Sets the password digest. - -void QXmppSaslServer::setPasswordDigest(const QByteArray &digest) -{ - d->passwordDigest = digest; -} - -/// Returns the realm. - -QString QXmppSaslServer::realm() const -{ - return d->realm; -} - -/// Sets the realm. - -void QXmppSaslServer::setRealm(const QString &realm) -{ - d->realm = realm; -} - -QXmppSaslServerAnonymous::QXmppSaslServerAnonymous(QObject *parent) - : QXmppSaslServer(parent) - , m_step(0) -{ -} - -QString QXmppSaslServerAnonymous::mechanism() const -{ - return "ANONYMOUS"; -} - -QXmppSaslServer::Response QXmppSaslServerAnonymous::respond(const QByteArray &request, QByteArray &response) -{ - Q_UNUSED(request); - if (m_step == 0) { - m_step++; - response = QByteArray(); - return Succeeded; - } else { - warning("QXmppSaslServerAnonymous : Invalid step"); - return Failed; - } -} - -QXmppSaslServerDigestMd5::QXmppSaslServerDigestMd5(QObject *parent) - : QXmppSaslServer(parent) - , m_step(0) -{ - m_nonce = generateNonce(); -} - -QString QXmppSaslServerDigestMd5::mechanism() const -{ - return "DIGEST-MD5"; -} - -QXmppSaslServer::Response QXmppSaslServerDigestMd5::respond(const QByteArray &request, QByteArray &response) -{ - if (m_step == 0) { - QMap output; - output["nonce"] = m_nonce; - if (!realm().isEmpty()) - output["realm"] = realm().toUtf8(); - output["qop"] = "auth"; - output["charset"] = "utf-8"; - output["algorithm"] = "md5-sess"; - - m_step++; - response = QXmppSaslDigestMd5::serializeMessage(output); - return Challenge; - } else if (m_step == 1) { - const QMap input = QXmppSaslDigestMd5::parseMessage(request); - const QByteArray realm = input.value("realm"); - const QByteArray digestUri = input.value("digest-uri"); - - if (input.value("qop") != "auth") { - warning("QXmppSaslServerDigestMd5 : Invalid quality of protection"); - return Failed; - } - - setUsername(QString::fromUtf8(input.value("username"))); - if (password().isEmpty() && passwordDigest().isEmpty()) - return InputNeeded; - - m_nc = input.value("nc"); - m_cnonce = input.value("cnonce"); - if (!password().isEmpty()) { - m_secret = QCryptographicHash::hash( - username().toUtf8() + ":" + realm + ":" + password().toUtf8(), - QCryptographicHash::Md5); - } else { - m_secret = passwordDigest(); - } - - if (input.value("response") != calculateDigest("AUTHENTICATE", digestUri, m_secret, m_nonce, m_cnonce, m_nc)) - return Failed; - - QMap output; - output["rspauth"] = calculateDigest(QByteArray(), digestUri, m_secret, m_nonce, m_cnonce, m_nc); - - m_step++; - response = QXmppSaslDigestMd5::serializeMessage(output); - return Challenge; - } else if (m_step == 2) { - m_step++; - response = QByteArray(); - return Succeeded; - } else { - warning("QXmppSaslServerDigestMd5 : Invalid step"); - return Failed; - } -} - -QXmppSaslServerPlain::QXmppSaslServerPlain(QObject *parent) - : QXmppSaslServer(parent) - , m_step(0) -{ -} - -QString QXmppSaslServerPlain::mechanism() const -{ - return "PLAIN"; -} - -QXmppSaslServer::Response QXmppSaslServerPlain::respond(const QByteArray &request, QByteArray &response) -{ - if (m_step == 0) { - QList auth = request.split('\0'); - if (auth.size() != 3) { - warning("QXmppSaslServerPlain : Invalid input"); - return Failed; - } - setUsername(QString::fromUtf8(auth[1])); - setPassword(QString::fromUtf8(auth[2])); - - m_step++; - response = QByteArray(); - return InputNeeded; - } else { - warning("QXmppSaslServerPlain : Invalid step"); - return Failed; - } -} - -void QXmppSaslDigestMd5::setNonce(const QByteArray &nonce) -{ - forcedNonce = nonce; -} - -QMap QXmppSaslDigestMd5::parseMessage(const QByteArray &ba) -{ - QMap map; - int startIndex = 0; - int pos = 0; - while ((pos = ba.indexOf("=", startIndex)) >= 0) - { - // key get name and skip equals - const QByteArray key = ba.mid(startIndex, pos - startIndex).trimmed(); - pos++; - - // check whether string is quoted - if (ba.at(pos) == '"') - { - // skip opening quote - pos++; - int endPos = ba.indexOf('"', pos); - // skip quoted quotes - while (endPos >= 0 && ba.at(endPos - 1) == '\\') - endPos = ba.indexOf('"', endPos + 1); - if (endPos < 0) - { - qWarning("Unfinished quoted string"); - return map; - } - // unquote - QByteArray value = ba.mid(pos, endPos - pos); - value.replace("\\\"", "\""); - value.replace("\\\\", "\\"); - map[key] = value; - // skip closing quote and comma - startIndex = endPos + 2; - } else { - // non-quoted string - int endPos = ba.indexOf(',', pos); - if (endPos < 0) - endPos = ba.size(); - map[key] = ba.mid(pos, endPos - pos); - // skip comma - startIndex = endPos + 1; - } - } - return map; -} - -QByteArray QXmppSaslDigestMd5::serializeMessage(const QMap &map) -{ - QByteArray ba; - foreach (const QByteArray &key, map.keys()) - { - if (!ba.isEmpty()) - ba.append(','); - ba.append(key + "="); - QByteArray value = map[key]; - const char *separators = "()<>@,;:\\\"/[]?={} \t"; - bool quote = false; - for (const char *c = separators; *c; c++) - { - if (value.contains(*c)) - { - quote = true; - break; - } - } - if (quote) - { - value.replace("\\", "\\\\"); - value.replace("\"", "\\\""); - ba.append("\"" + value + "\""); - } - else - ba.append(value); - } - return ba; -} - diff --git a/src/base/QXmppSaslAuth.h b/src/base/QXmppSaslAuth.h deleted file mode 100644 index f436cdf3..00000000 --- a/src/base/QXmppSaslAuth.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2008-2012 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - */ - -#ifndef QXMPPSASLAUTH_H -#define QXMPPSASLAUTH_H - -#include "QXmppGlobal.h" -#include "QXmppLogger.h" - -class QXmppSaslClientPrivate; -class QXmppSaslServerPrivate; - -/// The QXmppSaslClient class is the base class for all SASL client -/// authentication methods. - -class QXMPP_EXPORT QXmppSaslClient : public QXmppLoggable -{ -public: - QXmppSaslClient(QObject *parent = 0); - virtual ~QXmppSaslClient(); - - QString host() const; - void setHost(const QString &host); - - QString serviceType() const; - void setServiceType(const QString &serviceType); - - QString username() const; - void setUsername(const QString &username); - - QString password() const; - void setPassword(const QString &password); - - virtual QString mechanism() const = 0; - virtual bool respond(const QByteArray &challenge, QByteArray &response) = 0; - - static QStringList availableMechanisms(); - static QXmppSaslClient* create(const QString &mechanism, QObject *parent = 0); - -private: - QXmppSaslClientPrivate *d; -}; - -/// The QXmppServerClient class is the base class for all SASL server -/// authentication methods. - -class QXMPP_EXPORT QXmppSaslServer : public QXmppLoggable -{ -public: - enum Response { - Challenge = 0, - Succeeded = 1, - Failed = 2, - InputNeeded = 3 - }; - - QXmppSaslServer(QObject *parent = 0); - virtual ~QXmppSaslServer(); - - QString username() const; - void setUsername(const QString &username); - - QString password() const; - void setPassword(const QString &password); - - QByteArray passwordDigest() const; - void setPasswordDigest(const QByteArray &digest); - - QString realm() const; - void setRealm(const QString &realm); - - virtual QString mechanism() const = 0; - virtual Response respond(const QByteArray &challenge, QByteArray &response) = 0; - - static QXmppSaslServer* create(const QString &mechanism, QObject *parent = 0); - -private: - QXmppSaslServerPrivate *d; -}; - -#endif diff --git a/src/base/QXmppSaslAuth_p.h b/src/base/QXmppSaslAuth_p.h deleted file mode 100644 index 783e8b9b..00000000 --- a/src/base/QXmppSaslAuth_p.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2008-2012 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - */ - -#ifndef QXMPPSASLAUTH_P_H -#define QXMPPSASLAUTH_P_H - -#include -#include - -#include "QXmppStanza.h" - -// -// W A R N I N G -// ------------- -// -// This file is not part of the QXmpp API. It exists for the convenience -// of the QXmppSaslClient class. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -class QXmppSaslDigestMd5 -{ -public: - static void setNonce(const QByteArray &nonce); - - // message parsing and serialization - static QMap parseMessage(const QByteArray &ba); - static QByteArray serializeMessage(const QMap &map); -}; - -class QXmppSaslStanza : public QXmppStanza -{ -public: - QXmppSaslStanza(const QString &type, const QByteArray &value = QByteArray()); - - QString type() const; - void setType(const QString &type); - - QByteArray value() const; - void setValue(const QByteArray &value); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString m_type; - QByteArray m_value; -}; - -class QXmppSaslAuth : public QXmppSaslStanza -{ -public: - QXmppSaslAuth(const QString &mechanism = QString(), const QByteArray &value = QByteArray()); - - QString mechanism() const; - void setMechanism(const QString &mechanism); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString m_mechanism; -}; - -class QXmppSaslChallenge : public QXmppSaslStanza -{ -public: - QXmppSaslChallenge(const QByteArray &value = QByteArray()); -}; - -class QXmppSaslFailure : public QXmppSaslStanza -{ -public: - QXmppSaslFailure(const QString &condition = QString()); - - QString condition() const; - void setCondition(const QString &condition); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString m_condition; -}; - -class QXmppSaslResponse : public QXmppSaslStanza -{ -public: - QXmppSaslResponse(const QByteArray &value = QByteArray()); -}; - -class QXmppSaslSuccess : public QXmppSaslStanza -{ -public: - QXmppSaslSuccess(); -}; - -class QXmppSaslClientAnonymous : public QXmppSaslClient -{ -public: - QXmppSaslClientAnonymous(QObject *parent = 0); - QString mechanism() const; - bool respond(const QByteArray &challenge, QByteArray &response); - -private: - int m_step; -}; - -class QXmppSaslClientDigestMd5 : public QXmppSaslClient -{ -public: - QXmppSaslClientDigestMd5(QObject *parent = 0); - QString mechanism() const; - bool respond(const QByteArray &challenge, QByteArray &response); - -private: - QByteArray m_cnonce; - QByteArray m_nc; - QByteArray m_nonce; - QByteArray m_secret; - int m_step; -}; - -class QXmppSaslClientFacebook : public QXmppSaslClient -{ -public: - QXmppSaslClientFacebook(QObject *parent = 0); - QString mechanism() const; - bool respond(const QByteArray &challenge, QByteArray &response); - -private: - int m_step; -}; - -class QXmppSaslClientPlain : public QXmppSaslClient -{ -public: - QXmppSaslClientPlain(QObject *parent = 0); - QString mechanism() const; - bool respond(const QByteArray &challenge, QByteArray &response); - -private: - int m_step; -}; - -class QXmppSaslServerAnonymous : public QXmppSaslServer -{ -public: - QXmppSaslServerAnonymous(QObject *parent = 0); - QString mechanism() const; - - Response respond(const QByteArray &challenge, QByteArray &response); - -private: - int m_step; -}; - -class QXmppSaslServerDigestMd5 : public QXmppSaslServer -{ -public: - QXmppSaslServerDigestMd5(QObject *parent = 0); - QString mechanism() const; - - Response respond(const QByteArray &challenge, QByteArray &response); - -private: - QByteArray m_cnonce; - QByteArray m_nc; - QByteArray m_nonce; - QByteArray m_secret; - int m_step; -}; - -class QXmppSaslServerFacebook : public QXmppSaslServer -{ -public: - QXmppSaslServerFacebook(QObject *parent = 0); - QString mechanism() const; - - Response respond(const QByteArray &challenge, QByteArray &response); - -private: - int m_step; -}; - -class QXmppSaslServerPlain : public QXmppSaslServer -{ -public: - QXmppSaslServerPlain(QObject *parent = 0); - QString mechanism() const; - - Response respond(const QByteArray &challenge, QByteArray &response); - -private: - int m_step; -}; - -#endif diff --git a/src/base/QXmppSasl_p.h b/src/base/QXmppSasl_p.h new file mode 100644 index 00000000..636385ef --- /dev/null +++ b/src/base/QXmppSasl_p.h @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2008-2012 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#ifndef QXMPPSASL_P_H +#define QXMPPSASL_P_H + +#include +#include + +#include "QXmppGlobal.h" +#include "QXmppLogger.h" +#include "QXmppStanza.h" + +class QXmppSaslClientPrivate; +class QXmppSaslServerPrivate; + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QXmpp API. It exists for the convenience +// of the QXmppIncomingClient and QXmppOutgoingClient classes. +// +// This header file may change from version to version without notice, +// or even be removed. +// +// We mean it. +// + +class QXmppSaslClient : public QXmppLoggable +{ +public: + QXmppSaslClient(QObject *parent = 0); + virtual ~QXmppSaslClient(); + + QString host() const; + void setHost(const QString &host); + + QString serviceType() const; + void setServiceType(const QString &serviceType); + + QString username() const; + void setUsername(const QString &username); + + QString password() const; + void setPassword(const QString &password); + + virtual QString mechanism() const = 0; + virtual bool respond(const QByteArray &challenge, QByteArray &response) = 0; + + static QStringList availableMechanisms(); + static QXmppSaslClient* create(const QString &mechanism, QObject *parent = 0); + +private: + QXmppSaslClientPrivate *d; +}; + +/// The QXmppServerClient class is the base class for all SASL server +/// authentication methods. + +class QXmppSaslServer : public QXmppLoggable +{ +public: + enum Response { + Challenge = 0, + Succeeded = 1, + Failed = 2, + InputNeeded = 3 + }; + + QXmppSaslServer(QObject *parent = 0); + virtual ~QXmppSaslServer(); + + QString username() const; + void setUsername(const QString &username); + + QString password() const; + void setPassword(const QString &password); + + QByteArray passwordDigest() const; + void setPasswordDigest(const QByteArray &digest); + + QString realm() const; + void setRealm(const QString &realm); + + virtual QString mechanism() const = 0; + virtual Response respond(const QByteArray &challenge, QByteArray &response) = 0; + + static QXmppSaslServer* create(const QString &mechanism, QObject *parent = 0); + +private: + QXmppSaslServerPrivate *d; +}; + + +class QXmppSaslDigestMd5 +{ +public: + static void setNonce(const QByteArray &nonce); + + // message parsing and serialization + static QMap parseMessage(const QByteArray &ba); + static QByteArray serializeMessage(const QMap &map); +}; + +class QXmppSaslStanza : public QXmppStanza +{ +public: + QXmppSaslStanza(const QString &type, const QByteArray &value = QByteArray()); + + QString type() const; + void setType(const QString &type); + + QByteArray value() const; + void setValue(const QByteArray &value); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString m_type; + QByteArray m_value; +}; + +class QXmppSaslAuth : public QXmppSaslStanza +{ +public: + QXmppSaslAuth(const QString &mechanism = QString(), const QByteArray &value = QByteArray()); + + QString mechanism() const; + void setMechanism(const QString &mechanism); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString m_mechanism; +}; + +class QXmppSaslChallenge : public QXmppSaslStanza +{ +public: + QXmppSaslChallenge(const QByteArray &value = QByteArray()); +}; + +class QXmppSaslFailure : public QXmppSaslStanza +{ +public: + QXmppSaslFailure(const QString &condition = QString()); + + QString condition() const; + void setCondition(const QString &condition); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString m_condition; +}; + +class QXmppSaslResponse : public QXmppSaslStanza +{ +public: + QXmppSaslResponse(const QByteArray &value = QByteArray()); +}; + +class QXmppSaslSuccess : public QXmppSaslStanza +{ +public: + QXmppSaslSuccess(); +}; + +class QXmppSaslClientAnonymous : public QXmppSaslClient +{ +public: + QXmppSaslClientAnonymous(QObject *parent = 0); + QString mechanism() const; + bool respond(const QByteArray &challenge, QByteArray &response); + +private: + int m_step; +}; + +class QXmppSaslClientDigestMd5 : public QXmppSaslClient +{ +public: + QXmppSaslClientDigestMd5(QObject *parent = 0); + QString mechanism() const; + bool respond(const QByteArray &challenge, QByteArray &response); + +private: + QByteArray m_cnonce; + QByteArray m_nc; + QByteArray m_nonce; + QByteArray m_secret; + int m_step; +}; + +class QXmppSaslClientFacebook : public QXmppSaslClient +{ +public: + QXmppSaslClientFacebook(QObject *parent = 0); + QString mechanism() const; + bool respond(const QByteArray &challenge, QByteArray &response); + +private: + int m_step; +}; + +class QXmppSaslClientPlain : public QXmppSaslClient +{ +public: + QXmppSaslClientPlain(QObject *parent = 0); + QString mechanism() const; + bool respond(const QByteArray &challenge, QByteArray &response); + +private: + int m_step; +}; + +class QXmppSaslServerAnonymous : public QXmppSaslServer +{ +public: + QXmppSaslServerAnonymous(QObject *parent = 0); + QString mechanism() const; + + Response respond(const QByteArray &challenge, QByteArray &response); + +private: + int m_step; +}; + +class QXmppSaslServerDigestMd5 : public QXmppSaslServer +{ +public: + QXmppSaslServerDigestMd5(QObject *parent = 0); + QString mechanism() const; + + Response respond(const QByteArray &challenge, QByteArray &response); + +private: + QByteArray m_cnonce; + QByteArray m_nc; + QByteArray m_nonce; + QByteArray m_secret; + int m_step; +}; + +class QXmppSaslServerFacebook : public QXmppSaslServer +{ +public: + QXmppSaslServerFacebook(QObject *parent = 0); + QString mechanism() const; + + Response respond(const QByteArray &challenge, QByteArray &response); + +private: + int m_step; +}; + +class QXmppSaslServerPlain : public QXmppSaslServer +{ +public: + QXmppSaslServerPlain(QObject *parent = 0); + QString mechanism() const; + + Response respond(const QByteArray &challenge, QByteArray &response); + +private: + int m_step; +}; + +#endif diff --git a/src/base/base.pri b/src/base/base.pri index c50c49a6..21c3e138 100644 --- a/src/base/base.pri +++ b/src/base/base.pri @@ -28,7 +28,6 @@ INSTALL_HEADERS += \ base/QXmppRosterIq.h \ base/QXmppRpcIq.h \ base/QXmppRtpChannel.h \ - base/QXmppSaslAuth.h \ base/QXmppSessionIq.h \ base/QXmppSocks.h \ base/QXmppStanza.h \ @@ -68,7 +67,7 @@ SOURCES += \ base/QXmppRosterIq.cpp \ base/QXmppRpcIq.cpp \ base/QXmppRtpChannel.cpp \ - base/QXmppSaslAuth.cpp \ + base/QXmppSasl.cpp \ base/QXmppSessionIq.cpp \ base/QXmppSocks.cpp \ base/QXmppStanza.cpp \ -- cgit v1.2.3