diff options
| author | Jeremy Lainé <jeremy.laine@m4x.org> | 2012-07-20 10:59:53 +0200 |
|---|---|---|
| committer | Jeremy Lainé <jeremy.laine@m4x.org> | 2012-07-20 10:59:53 +0200 |
| commit | 15cab790071aabfc62977d590b89f54a5fa6e92d (patch) | |
| tree | 4b75e1269ab983d06130340325a4ee97baf901e7 | |
| parent | a609100c2a0eb19ef4b9c7a571366281ca722ac8 (diff) | |
| download | qxmpp-15cab790071aabfc62977d590b89f54a5fa6e92d.tar.gz | |
first stab at factoring out server-side SASL
| -rw-r--r-- | src/base/QXmppSaslAuth.cpp | 149 | ||||
| -rw-r--r-- | src/base/QXmppSaslAuth.h | 28 | ||||
| -rw-r--r-- | src/base/QXmppSaslAuth_p.h | 49 | ||||
| -rw-r--r-- | tests/sasl.cpp | 68 | ||||
| -rw-r--r-- | tests/sasl.h | 12 | ||||
| -rw-r--r-- | tests/tests.cpp | 7 |
6 files changed, 309 insertions, 4 deletions
diff --git a/src/base/QXmppSaslAuth.cpp b/src/base/QXmppSaslAuth.cpp index 0ae3b1df..ead1188f 100644 --- a/src/base/QXmppSaslAuth.cpp +++ b/src/base/QXmppSaslAuth.cpp @@ -104,7 +104,7 @@ void QXmppSaslClient::setServiceType(const QString &serviceType) d->serviceType = serviceType; } -/// Returns the host. +/// Returns the username. QString QXmppSaslClient::username() const { @@ -308,6 +308,153 @@ bool QXmppSaslClientPlain::respond(const QByteArray &challenge, QByteArray &resp } } +class QXmppSaslServerPrivate +{ +public: + QString username; + QString password; +}; + +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); + } +} + +/// 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; +} + +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) +{ +} + +QString QXmppSaslServerDigestMd5::mechanism() const +{ + return "DIGEST-MD5"; +} + +QXmppSaslServer::Response QXmppSaslServerDigestMd5::respond(const QByteArray &request, QByteArray &response) +{ + if (m_step == 0) { + // generate nonce + m_saslDigest.setNonce(QXmppSaslDigestMd5::generateNonce()); + //m_saslDigest.setQop("auth"); + + QMap<QByteArray, QByteArray> challenge; + challenge["nonce"] = m_saslDigest.nonce(); + //challenge["realm"] = m_domain.toUtf8(); + challenge["qop"] = "auth"; + challenge["charset"] = "utf-8"; + challenge["algorithm"] = "md5-sess"; + + m_step++; + response = QXmppSaslDigestMd5::serializeMessage(challenge); + return Challenge; + } else { + 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<QByteArray> 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 Succeeded; + } else { + warning("QXmppSaslServerPlain : Invalid step"); + return Failed; + } +} + QByteArray QXmppSaslDigestMd5::authzid() const { return m_authzid; diff --git a/src/base/QXmppSaslAuth.h b/src/base/QXmppSaslAuth.h index b6428eb8..9026d757 100644 --- a/src/base/QXmppSaslAuth.h +++ b/src/base/QXmppSaslAuth.h @@ -32,6 +32,7 @@ #include "QXmppLogger.h" class QXmppSaslClientPrivate; +class QXmppSaslServerPrivate; class QXMPP_EXPORT QXmppSaslDigestMd5 { @@ -105,4 +106,31 @@ private: QXmppSaslClientPrivate *d; }; +class QXMPP_EXPORT QXmppSaslServer : public QXmppLoggable +{ +public: + enum Response { + Challenge = 0, + Succeeded = 1, + Failed = 2 + }; + + QXmppSaslServer(QObject *parent = 0); + virtual ~QXmppSaslServer(); + + QString username() const; + void setUsername(const QString &username); + + QString password() const; + void setPassword(const QString &password); + + 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 index 18c1829e..10a20cfb 100644 --- a/src/base/QXmppSaslAuth_p.h +++ b/src/base/QXmppSaslAuth_p.h @@ -81,4 +81,53 @@ 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: + QXmppSaslDigestMd5 m_saslDigest; + 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/tests/sasl.cpp b/tests/sasl.cpp index e2dd8486..622bccb6 100644 --- a/tests/sasl.cpp +++ b/tests/sasl.cpp @@ -31,6 +31,12 @@ void tst_QXmppSaslClient::testAvailableMechanisms() QCOMPARE(QXmppSaslClient::availableMechanisms(), QStringList() << "PLAIN" << "DIGEST-MD5" << "ANONYMOUS" << "X-FACEBOOK-PLATFORM"); } +void tst_QXmppSaslClient::testBadMechanism() +{ + QXmppSaslClient *client = QXmppSaslClient::create("BAD-MECH"); + QVERIFY(client == 0); +} + void tst_QXmppSaslClient::testAnonymous() { QXmppSaslClient *client = QXmppSaslClient::create("ANONYMOUS"); @@ -41,7 +47,7 @@ void tst_QXmppSaslClient::testAnonymous() QByteArray response; QVERIFY(client->respond(QByteArray(), response)); QCOMPARE(response, QByteArray()); - + // any further step is an error QVERIFY(!client->respond(QByteArray(), response)); @@ -131,3 +137,63 @@ void tst_QXmppSaslClient::testPlain() delete client; } +void tst_QXmppSaslServer::testBadMechanism() +{ + QXmppSaslServer *server = QXmppSaslServer::create("BAD-MECH"); + QVERIFY(server == 0); +} + +void tst_QXmppSaslServer::testAnonymous() +{ + QXmppSaslServer *server = QXmppSaslServer::create("ANONYMOUS"); + QVERIFY(server != 0); + QCOMPARE(server->mechanism(), QLatin1String("ANONYMOUS")); + + // initial step returns success + QByteArray response; + QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Succeeded); + QCOMPARE(response, QByteArray()); + + // any further step is an error + QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Failed); + + delete server; +} + +void tst_QXmppSaslServer::testDigestMd5() +{ + qsrand(0); + + QXmppSaslServer *server = QXmppSaslServer::create("DIGEST-MD5"); + QVERIFY(server != 0); + QCOMPARE(server->mechanism(), QLatin1String("DIGEST-MD5")); + + // initial step returns challenge + QByteArray response; + QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Challenge); + QCOMPARE(response, QByteArray("algorithm=md5-sess,charset=utf-8,nonce=\"AMzVG8Oibf+sVUCPPlWLR8lZQvbbJtJB9vJd+u3c6dw=\",qop=auth")); + + // any further step is an error + QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Failed); + + delete server; +} + +void tst_QXmppSaslServer::testPlain() +{ + QXmppSaslServer *server = QXmppSaslServer::create("PLAIN"); + QVERIFY(server != 0); + QCOMPARE(server->mechanism(), QLatin1String("PLAIN")); + + // initial step returns success + QByteArray response; + QCOMPARE(server->respond(QByteArray("\0foo\0bar", 8), response), QXmppSaslServer::Succeeded); + QCOMPARE(response, QByteArray()); + QCOMPARE(server->username(), QLatin1String("foo")); + QCOMPARE(server->password(), QLatin1String("bar")); + + // any further step is an error + QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Failed); + + delete server; +} diff --git a/tests/sasl.h b/tests/sasl.h index e6db2b01..b1bb7603 100644 --- a/tests/sasl.h +++ b/tests/sasl.h @@ -29,6 +29,7 @@ class tst_QXmppSaslClient : public QObject private slots: void testAvailableMechanisms(); + void testBadMechanism(); void testAnonymous(); void testDigestMd5(); void testDigestMd5_data(); @@ -36,3 +37,14 @@ private slots: void testPlain(); }; +class tst_QXmppSaslServer : public QObject +{ + Q_OBJECT + +private slots: + void testBadMechanism(); + void testAnonymous(); + void testDigestMd5(); + void testPlain(); +}; + diff --git a/tests/tests.cpp b/tests/tests.cpp index 49a60613..acb6b145 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -1378,8 +1378,11 @@ int main(int argc, char *argv[]) tst_QXmppRtpPacket testRtp; errors += QTest::qExec(&testRtp); - tst_QXmppSaslClient testSasl; - errors += QTest::qExec(&testSasl); + tst_QXmppSaslClient testSaslClient; + errors += QTest::qExec(&testSaslClient); + + tst_QXmppSaslServer testSaslServer; + errors += QTest::qExec(&testSaslServer); TestServer testServer; errors += QTest::qExec(&testServer); |
