File indexing completed on 2024-05-12 05:17:20

0001 /*
0002    Copyright (C) 2009 Andras Mantia <amantia@kde.org>
0003 
0004    Copyright (c) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
0005    Author: Kevin Ottens <kevin@kdab.com>
0006 
0007    This program is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU General Public
0009    License as published by the Free Software Foundation; either
0010    version 2 of the License, or (at your option) any later version.
0011 
0012    This program is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015    General Public License for more details.
0016 
0017    You should have received a copy of the GNU General Public License
0018    along with this program; if not, write to the Free Software
0019    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include <qtest.h>
0023 
0024 #include "kimap2test/fakeserver.h"
0025 #include "kimap2/session.h"
0026 #include "kimap2/loginjob.h"
0027 
0028 #include <QtTest>
0029 
0030 class LoginJobTest: public QObject
0031 {
0032     Q_OBJECT
0033 
0034 private Q_SLOTS:
0035 
0036     void shouldHandleLogin_data()
0037     {
0038         QTest::addColumn<QString>("user");
0039         QTest::addColumn<QString>("password");
0040         QTest::addColumn< QList<QByteArray> >("scenario");
0041 
0042         QList<QByteArray> scenario;
0043         scenario << FakeServer::greeting()
0044                  << "C: A000001 CAPABILITY"
0045                  << "S: A000001 OK"
0046                  << "C: A000002 LOGIN \"user\" \"password\""
0047                  << "S: A000002 OK User logged in";
0048 
0049         QTest::newRow("success") << "user" << "password" << scenario;
0050 
0051         scenario.clear();
0052         scenario << FakeServer::greeting()
0053                  << "C: A000001 CAPABILITY"
0054                  << "S: A000001 OK"
0055                  << "C: A000002 LOGIN \"user_bad\" \"password\""
0056                  << "S: A000002 NO Login failed: authentication failure";
0057 
0058         QTest::newRow("wrong login") << "user_bad" << "password" << scenario;
0059 
0060         scenario.clear();
0061         scenario << FakeServer::greeting()
0062                  << "C: A000001 CAPABILITY"
0063                  << "S: A000001 OK"
0064                  << "C: A000002 LOGIN \"user\" \"aa\\\"bb\\\\cc[dd ee\""
0065                  << "S: A000002 OK User logged in";
0066 
0067         QTest::newRow("special chars") << "user" << "aa\"bb\\cc[dd ee" << scenario;
0068 
0069         scenario.clear();
0070         scenario << FakeServer::preauth();
0071 
0072         QTest::newRow("already authenticated") << "user" << "password" << scenario;
0073     }
0074 
0075     void shouldHandleLogin()
0076     {
0077         QFETCH(QString, user);
0078         QFETCH(QString, password);
0079         QFETCH(QList<QByteArray>, scenario);
0080 
0081         FakeServer fakeServer;
0082         fakeServer.setScenario(scenario);
0083         fakeServer.startAndWait();
0084 
0085         KIMAP2::Session *session = new KIMAP2::Session("127.0.0.1", 5989);
0086 
0087         KIMAP2::LoginJob *login = new KIMAP2::LoginJob(session);
0088         login->setUserName(user);
0089         login->setPassword(password);
0090         bool result = login->exec();
0091 
0092         QEXPECT_FAIL("wrong login", "Login with bad user name", Continue);
0093         QEXPECT_FAIL("already authenticated", "Trying to log on an already authenticated session", Continue);
0094         QVERIFY(result);
0095 
0096         fakeServer.quit();
0097         delete session;
0098     }
0099 
0100     void shouldHandleProxyLogin_data()
0101     {
0102         QTest::addColumn<QString>("user");
0103         QTest::addColumn<QString>("proxy");
0104         QTest::addColumn<QString>("password");
0105         QTest::addColumn< QList<QByteArray> >("scenario");
0106 
0107         QList<QByteArray> scenario;
0108         scenario << FakeServer::greeting()
0109                  << "C: A000001 CAPABILITY"
0110                  << "S: A000001 OK"
0111                  << "C: A000002 AUTHENTICATE PLAIN"
0112                  << "S: A000002 OK (success)"
0113                  << "C: A000003 LOGIN \"proxy\" \"user\" \"password\""
0114                  << "S: A000003 OK User logged in";
0115 
0116         QTest::newRow("success") << "user" << "proxy" << "password" << scenario;
0117     }
0118 
0119     void shouldHandleProxyLogin()
0120     {
0121         QFETCH(QString, user);
0122         QFETCH(QString, proxy);
0123         QFETCH(QString, password);
0124         QFETCH(QList<QByteArray>, scenario);
0125 
0126         FakeServer fakeServer;
0127         fakeServer.setScenario(scenario);
0128         fakeServer.startAndWait();
0129 
0130         KIMAP2::Session *session = new KIMAP2::Session("127.0.0.1", 5989);
0131 
0132         KIMAP2::LoginJob *login = new KIMAP2::LoginJob(session);
0133         login->setAuthenticationMode(KIMAP2::LoginJob::Plain);
0134         login->setUserName(user);
0135         login->setAuthorizationName(proxy);
0136         login->setPassword(password);
0137         bool result = login->exec();
0138 
0139         QVERIFY(result);
0140 
0141         fakeServer.quit();
0142         delete session;
0143     }
0144 
0145     void shouldSaveServerGreeting_data()
0146     {
0147         QTest::addColumn<QString>("greeting");
0148         QTest::addColumn< QList<QByteArray> >("scenario");
0149 
0150         QList<QByteArray> scenario;
0151         scenario << FakeServer::greeting()
0152                  << "C: A000001 CAPABILITY"
0153                  << "S: A000001 OK"
0154                  << "C: A000002 LOGIN \"user\" \"password\""
0155                  << "S: A000002 OK Welcome John Smith";
0156 
0157         QTest::newRow("greeting") << "Welcome John Smith" << scenario;
0158 
0159         scenario.clear();
0160         scenario << FakeServer::greeting()
0161                  << "C: A000001 CAPABILITY"
0162                  << "S: A000001 OK"
0163                  << "C: A000002 LOGIN \"user\" \"password\""
0164                  << "S: A000002 OK Welcome John Smith (last login: Feb 21, 2010)";
0165 
0166         QTest::newRow("greeting with parenthesis") << "Welcome John Smith (last login: Feb 21, 2010)" << scenario;
0167 
0168         scenario.clear();
0169         scenario << FakeServer::greeting()
0170                  << "C: A000001 CAPABILITY"
0171                  << "S: A000001 OK"
0172                  << "C: A000002 LOGIN \"user\" \"password\""
0173                  << "S: A000002 OK";
0174 
0175         QTest::newRow("no greeting") << "" << scenario;
0176 
0177         scenario.clear();
0178         scenario << FakeServer::greeting()
0179                  << "C: A000001 CAPABILITY"
0180                  << "S: A000001 OK"
0181                  << "C: A000002 LOGIN \"user\" \"password\""
0182                  << "S: A000002 NO Login failed: authentication failure";
0183 
0184         QTest::newRow("login failed") << "" << scenario;
0185     }
0186 
0187     void shouldSaveServerGreeting()
0188     {
0189         QFETCH(QString, greeting);
0190         QFETCH(QList<QByteArray>, scenario);
0191 
0192         FakeServer fakeServer;
0193         fakeServer.setScenario(scenario);
0194         fakeServer.startAndWait();
0195 
0196         KIMAP2::Session *session = new KIMAP2::Session("127.0.0.1", 5989);
0197 
0198         KIMAP2::LoginJob *login = new KIMAP2::LoginJob(session);
0199         login->setUserName("user");
0200         login->setPassword("password");
0201         login->exec();
0202 
0203         QCOMPARE(login->serverGreeting(), greeting);
0204 
0205         fakeServer.quit();
0206         delete session;
0207     }
0208 
0209     void shouldUseSsl_data()
0210     {
0211         QTest::addColumn< QList<QByteArray> >("scenario");
0212         QTest::addColumn< int >("serverEncryption");
0213         QTest::addColumn< int >("clientEncryption");
0214         QTest::addColumn< bool >("startTls");
0215 
0216         {
0217             QList<QByteArray> scenario;
0218             scenario << FakeServer::greeting()
0219                      << "C: A000001 STARTTLS"
0220                      << "S: A000001 OK"
0221                      << "C: A000002 CAPABILITY"
0222                      << "S: A000002 OK"
0223                      << "C: A000003 LOGIN \"user\" \"password\""
0224                      << "S: A000003 OK";
0225 
0226             QTest::newRow("starttls tlsv1.0") << scenario << static_cast<int>(QSsl::TlsV1_0) << static_cast<int>(QSsl::TlsV1_0) << true;
0227             QTest::newRow("starttls tlsv1.1") << scenario << static_cast<int>(QSsl::TlsV1_1) << static_cast<int>(QSsl::TlsV1_1) << true;
0228             QTest::newRow("starttls tlsv1.2") << scenario << static_cast<int>(QSsl::TlsV1_2) << static_cast<int>(QSsl::TlsV1_2) << true;
0229         }
0230         {
0231             QList<QByteArray> scenario;
0232             scenario << FakeServer::greeting()
0233                      << "C: A000001 CAPABILITY"
0234                      << "S: A000001 OK"
0235                      << "C: A000002 LOGIN \"user\" \"password\""
0236                      << "S: A000002 OK";
0237 
0238             //sslv3 is no longer supported by qsslsocket
0239             // QTest::newRow("sslv3") << scenario << static_cast<int>(QSsl::SslV3) << static_cast<int>(QSsl::SslV3) << false;
0240             //sslv2 is no longer supported by qsslsocket
0241             // QTest::newRow("sslv2") << scenario << static_cast<int>(QSsl::SslV2) << static_cast<int>(KIMAP2::LoginJob::SslV2);
0242             //AnyProtocol doesn't mean the server can force a specific version (e.g. openssl always starts with a sslv2 hello)
0243             QTest::newRow("any protocol with anyssl version") << scenario << static_cast<int>(QSsl::AnyProtocol) << static_cast<int>(QSsl::AnyProtocol) << false;
0244             QTest::newRow("tlsv1.0") << scenario << static_cast<int>(QSsl::TlsV1_0) << static_cast<int>(QSsl::TlsV1_0) << false;
0245         }
0246     }
0247 
0248     void shouldUseSsl()
0249     {
0250         QSKIP("Test broken");
0251 
0252         QFETCH(QList<QByteArray>, scenario);
0253         QFETCH(int, serverEncryption);
0254         QFETCH(int, clientEncryption);
0255         QFETCH(bool, startTls);
0256 
0257         FakeServer fakeServer;
0258         fakeServer.setEncrypted(static_cast<QSsl::SslProtocol>(serverEncryption), startTls);
0259         fakeServer.setScenario(scenario);
0260         fakeServer.startAndWait();
0261 
0262         KIMAP2::Session *session = new KIMAP2::Session("127.0.0.1", 5989);
0263 
0264         QObject::connect(session, &KIMAP2::Session::sslErrors, [session](const QList<QSslError> &errors) {
0265             qWarning() << "Got ssl error: " << errors;
0266             session->ignoreErrors(errors);
0267         });
0268 
0269         KIMAP2::LoginJob *login = new KIMAP2::LoginJob(session);
0270         login->setUserName("user");
0271         login->setPassword("password");
0272         login->setEncryptionMode(static_cast<QSsl::SslProtocol>(clientEncryption), startTls);
0273         QVERIFY(login->exec());
0274 
0275         fakeServer.quit();
0276         delete session;
0277     }
0278 
0279     void shouldFailOnWrongSslSettings_data()
0280     {
0281         QTest::addColumn< QList<QByteArray> >("scenario");
0282         QTest::addColumn< int >("serverEncryption");
0283         QTest::addColumn< int >("clientEncryption");
0284         QTest::addColumn< int >("expectedErrorCode");
0285 
0286         {
0287             QList<QByteArray> scenario;
0288             scenario << FakeServer::greeting();
0289 
0290             //For some reason only connecting to tlsv1 results in an ssl handshake error, with the wrong version only the server detects the error and disconnects
0291 //     QTest::newRow( "ssl v3 v2" ) << scenario << static_cast<int>(QSsl::SslV3) << static_cast<int>(KIMAP2::LoginJob::SslV2) << static_cast<int>(KJob::UserDefinedError);
0292             QTest::newRow("ssl tlsv1 v3") << scenario << static_cast<int>(QSsl::SslV3) << static_cast<int>(QSsl::TlsV1_0) << static_cast<int>(KIMAP2::SslHandshakeFailed);
0293         }
0294     }
0295 
0296     void shouldFailOnWrongSslSettings()
0297     {
0298         QFETCH(QList<QByteArray>, scenario);
0299         QFETCH(int, serverEncryption);
0300         Q_UNUSED(serverEncryption);
0301         QFETCH(int, clientEncryption);
0302         QFETCH(int, expectedErrorCode);
0303 
0304         FakeServer fakeServer;
0305         fakeServer.setScenario(scenario);
0306         fakeServer.startAndWait();
0307 
0308         KIMAP2::Session *session = new KIMAP2::Session("127.0.0.1", 5989);
0309 
0310         QObject::connect(session, &KIMAP2::Session::sslErrors, [session](const QList<QSslError> &errors) {
0311             qWarning() << "Got ssl error: " << errors;
0312             session->ignoreErrors(errors);
0313         });
0314 
0315         KIMAP2::LoginJob *login = new KIMAP2::LoginJob(session);
0316         login->setUserName("user");
0317         login->setPassword("password");
0318         login->setEncryptionMode(static_cast<QSsl::SslProtocol>(clientEncryption), false);
0319         QVERIFY(!login->exec());
0320         QCOMPARE(static_cast<int>(login->error()), expectedErrorCode);
0321 
0322         fakeServer.quit();
0323         delete session;
0324     }
0325 
0326 };
0327 
0328 QTEST_GUILESS_MAIN(LoginJobTest)
0329 
0330 #include "loginjobtest.moc"