aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Lainé <jeremy.laine@m4x.org>2011-03-29 13:20:14 +0000
committerJeremy Lainé <jeremy.laine@m4x.org>2011-03-29 13:20:14 +0000
commit75a0cb2036ebd6c1913caec6d4d9c4497481ec2f (patch)
tree2119507630d04f09c90fe05138e866fa3c88ba69
parent4f738fbb73b3b15b6022635b78dac71f91909cd0 (diff)
downloadqxmpp-75a0cb2036ebd6c1913caec6d4d9c4497481ec2f.tar.gz
refactor SASL authentication to allow server-side password checkers which natively support MD5
-rw-r--r--examples/example_8_server/main.cpp13
-rw-r--r--src/QXmppIncomingClient.cpp50
-rw-r--r--src/QXmppIncomingClient.h11
-rw-r--r--src/QXmppOutgoingClient.cpp13
-rw-r--r--src/QXmppSaslAuth.cpp28
-rw-r--r--src/QXmppSaslAuth.h12
-rw-r--r--tests/tests.cpp13
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;