diff options
| author | Jeremy Lainé <jeremy.laine@m4x.org> | 2011-03-29 13:20:14 +0000 |
|---|---|---|
| committer | Jeremy Lainé <jeremy.laine@m4x.org> | 2011-03-29 13:20:14 +0000 |
| commit | 75a0cb2036ebd6c1913caec6d4d9c4497481ec2f (patch) | |
| tree | 2119507630d04f09c90fe05138e866fa3c88ba69 | |
| parent | 4f738fbb73b3b15b6022635b78dac71f91909cd0 (diff) | |
| download | qxmpp-75a0cb2036ebd6c1913caec6d4d9c4497481ec2f.tar.gz | |
refactor SASL authentication to allow server-side password checkers which natively support MD5
| -rw-r--r-- | examples/example_8_server/main.cpp | 13 | ||||
| -rw-r--r-- | src/QXmppIncomingClient.cpp | 50 | ||||
| -rw-r--r-- | src/QXmppIncomingClient.h | 11 | ||||
| -rw-r--r-- | src/QXmppOutgoingClient.cpp | 13 | ||||
| -rw-r--r-- | src/QXmppSaslAuth.cpp | 28 | ||||
| -rw-r--r-- | src/QXmppSaslAuth.h | 12 | ||||
| -rw-r--r-- | tests/tests.cpp | 13 |
7 files changed, 64 insertions, 76 deletions
diff --git a/examples/example_8_server/main.cpp b/examples/example_8_server/main.cpp index 8dadcc18..ed1f814e 100644 --- a/examples/example_8_server/main.cpp +++ b/examples/example_8_server/main.cpp @@ -32,18 +32,11 @@ class passwordChecker : public QXmppPasswordChecker { - /// Checks that the given credentials are valid. - QXmppPasswordChecker::Error checkPassword(const QString &username, const QString &password) - { - if (username == USERNAME && password == PASSWORD) - return QXmppPasswordChecker::NoError; - else - return QXmppPasswordChecker::AuthorizationError; - }; - /// Retrieves the password for the given username. - bool getPassword(const QString &username, QString &password) + bool getPassword(const QString &username, const QString &domain, QString &password) { + Q_UNUSED(domain); + if (username == USERNAME) { password = PASSWORD; diff --git a/src/QXmppIncomingClient.cpp b/src/QXmppIncomingClient.cpp index e27365fd..cb71024d 100644 --- a/src/QXmppIncomingClient.cpp +++ b/src/QXmppIncomingClient.cpp @@ -21,6 +21,7 @@ * */ +#include <QCryptographicHash> #include <QDomElement> #include <QSslKey> #include <QSslSocket> @@ -223,7 +224,7 @@ void QXmppIncomingClient::handleStanza(const QDomElement &nodeRecv) return; } - QXmppPasswordChecker::Error error = d->passwordChecker->checkPassword(username, password); + QXmppPasswordChecker::Error error = d->passwordChecker->checkPassword(username, d->domain, password); if (error == QXmppPasswordChecker::NoError) { d->username = username; @@ -246,12 +247,11 @@ void QXmppIncomingClient::handleStanza(const QDomElement &nodeRecv) // generate nonce d->saslDigest.setNonce(QXmppSaslDigestMd5::generateNonce()); d->saslDigest.setQop("auth"); - d->saslDigest.setRealm(d->domain.toUtf8()); d->saslStep = 1; QMap<QByteArray, QByteArray> challenge; challenge["nonce"] = d->saslDigest.nonce(); - challenge["realm"] = d->saslDigest.realm(); + challenge["realm"] = d->domain.toUtf8(); challenge["qop"] = d->saslDigest.qop(); challenge["charset"] = "utf-8"; challenge["algorithm"] = "md5-sess"; @@ -276,15 +276,14 @@ void QXmppIncomingClient::handleStanza(const QDomElement &nodeRecv) { // check credentials const QString username = QString::fromUtf8(response.value("username")); - QString password; - if (!d->passwordChecker || !d->passwordChecker->getPassword(username, password)) + QByteArray secret; + if (!d->passwordChecker || !d->passwordChecker->getDigest(username, d->domain, secret)) { - sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>"); + sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><temporary-auth-failure/></failure>"); disconnectFromHost(); return; } - d->saslDigest.setUsername(username.toUtf8()); - d->saslDigest.setPassword(password.toUtf8()); + d->saslDigest.setSecret(secret); d->saslDigest.setDigestUri(response.value("digest-uri")); d->saslDigest.setNc(response.value("nc")); d->saslDigest.setCnonce(response.value("cnonce")); @@ -393,16 +392,49 @@ void QXmppIncomingClient::slotTimeout() disconnectFromHost(); } +/// Checks that the given credentials are valid. +/// +/// \param username +/// \param domain +/// \param password + +QXmppPasswordChecker::Error QXmppPasswordChecker::checkPassword(const QString &username, const QString &domain, const QString &password) +{ + QString secret; + if (!getPassword(username, domain, secret)) + return TemporaryError; + + return (password == secret) ? NoError : AuthorizationError; +} + +/// Retrieves the MD5 digest for the given username. +/// +/// \param username + +bool QXmppPasswordChecker::getDigest(const QString &username, const QString &domain, QByteArray &digest) +{ + QString password; + if (!getPassword(username, domain, password)) + return false; + + digest = QCryptographicHash::hash( + (username + ":" + domain + ":" + password).toUtf8(), + QCryptographicHash::Md5); + return true; +} + /// Retrieves the password for the given username. /// /// You need to reimplement this method to support DIGEST-MD5 authentication. /// /// \param username +/// \param domain /// \param password -bool QXmppPasswordChecker::getPassword(const QString &username, QString &password) +bool QXmppPasswordChecker::getPassword(const QString &username, const QString &domain, QString &password) { Q_UNUSED(username); + Q_UNUSED(domain); Q_UNUSED(password); return false; } diff --git a/src/QXmppIncomingClient.h b/src/QXmppIncomingClient.h index a5ffbf38..9b053f6a 100644 --- a/src/QXmppIncomingClient.h +++ b/src/QXmppIncomingClient.h @@ -41,13 +41,12 @@ public: TemporaryError, }; - /// Checks that the given credentials are valid. - /// - /// \param username - /// \param password - virtual Error checkPassword(const QString &username, const QString &password) = 0; - virtual bool getPassword(const QString &username, QString &password); + virtual Error checkPassword(const QString &username, const QString &domain, const QString &password); + virtual bool getDigest(const QString &username, const QString &domain, QByteArray &digest); virtual bool hasGetPassword() const; + +protected: + virtual bool getPassword(const QString &username, const QString &domain, QString &password); }; /// \brief The QXmppIncomingClient class represents an incoming XMPP stream diff --git a/src/QXmppOutgoingClient.cpp b/src/QXmppOutgoingClient.cpp index 0c2af465..fdb3cc8a 100644 --- a/src/QXmppOutgoingClient.cpp +++ b/src/QXmppOutgoingClient.cpp @@ -22,6 +22,7 @@ * */ +#include <QCryptographicHash> #include <QSslSocket> #include "QXmppConfiguration.h" @@ -615,15 +616,15 @@ void QXmppOutgoingClient::sendAuthDigestMD5ResponseStep1(const QString& challeng d->saslDigest.setNc("00000001"); d->saslDigest.setNonce(map.value("nonce")); d->saslDigest.setQop("auth"); - d->saslDigest.setRealm(map.value("realm")); - d->saslDigest.setUsername(configuration().user().toUtf8()); - d->saslDigest.setPassword(configuration().password().toUtf8()); + d->saslDigest.setSecret(QCryptographicHash::hash( + configuration().user().toUtf8() + ":" + map.value("realm") + ":" + configuration().password().toUtf8(), + QCryptographicHash::Md5)); // Build response QMap<QByteArray, QByteArray> response; - response["username"] = d->saslDigest.username(); - if(!d->saslDigest.realm().isEmpty()) - response["realm"] = d->saslDigest.realm(); + response["username"] = configuration().user().toUtf8(); + if (map.contains("realm")) + response["realm"] = map.value("realm"); response["nonce"] = d->saslDigest.nonce(); response["cnonce"] = d->saslDigest.cnonce(); response["nc"] = d->saslDigest.nc(); diff --git a/src/QXmppSaslAuth.cpp b/src/QXmppSaslAuth.cpp index c40ff1a2..9543ea02 100644 --- a/src/QXmppSaslAuth.cpp +++ b/src/QXmppSaslAuth.cpp @@ -89,29 +89,9 @@ void QXmppSaslDigestMd5::setQop(const QByteArray &qop) m_qop = qop; } -QByteArray QXmppSaslDigestMd5::realm() const +void QXmppSaslDigestMd5::setSecret(const QByteArray &secret) { - return m_realm; -} - -void QXmppSaslDigestMd5::setRealm(const QByteArray &realm) -{ - m_realm = realm; -} - -QByteArray QXmppSaslDigestMd5::username() const -{ - return m_username; -} - -void QXmppSaslDigestMd5::setUsername(const QByteArray &username) -{ - m_username = username; -} - -void QXmppSaslDigestMd5::setPassword(const QByteArray &password) -{ - m_password = password; + m_secret = secret; } QByteArray QXmppSaslDigestMd5::generateNonce() @@ -130,9 +110,7 @@ QByteArray QXmppSaslDigestMd5::generateNonce() QByteArray QXmppSaslDigestMd5::calculateDigest(const QByteArray &A2) const { - const QByteArray a1 = m_username + ':' + m_realm + ':' + m_password; - QByteArray ha1 = QCryptographicHash::hash(a1, QCryptographicHash::Md5); - ha1 += ':' + m_nonce + ':' + m_cnonce; + QByteArray ha1 = m_secret + ':' + m_nonce + ':' + m_cnonce; if (!m_authzid.isEmpty()) ha1 += ':' + m_authzid; diff --git a/src/QXmppSaslAuth.h b/src/QXmppSaslAuth.h index affc5d4a..409636cb 100644 --- a/src/QXmppSaslAuth.h +++ b/src/QXmppSaslAuth.h @@ -49,13 +49,7 @@ public: QByteArray qop() const; void setQop(const QByteArray &qop); - QByteArray realm() const; - void setRealm(const QByteArray &realm); - - QByteArray username() const; - void setUsername(const QByteArray &username); - - void setPassword(const QByteArray &password); + void setSecret(const QByteArray &secret); QByteArray calculateDigest(const QByteArray &A2) const; QByteArray calculateDigest(const QByteArray &A1, const QByteArray &A2) const; @@ -72,9 +66,7 @@ private: QByteArray m_nc; QByteArray m_nonce; QByteArray m_qop; - QByteArray m_realm; - QByteArray m_username; - QByteArray m_password; + QByteArray m_secret; }; #endif diff --git a/tests/tests.cpp b/tests/tests.cpp index ed080cac..f7bb98af 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -940,18 +940,11 @@ public: { }; - /// Checks that the given credentials are valid. - QXmppPasswordChecker::Error checkPassword(const QString &username, const QString &password) - { - if (username == m_username && password == m_password) - return QXmppPasswordChecker::NoError; - else - return QXmppPasswordChecker::AuthorizationError; - }; - /// Retrieves the password for the given username. - bool getPassword(const QString &username, QString &password) + bool getPassword(const QString &username, const QString &domain, QString &password) { + Q_UNUSED(domain); + if (username == m_username) { password = m_password; |
