Merge PR #594: Bind a client connection to the token given in the hello call.

This commit is contained in:
jenkins 2023-02-21 17:43:20 +01:00
commit 0ca34e91c3
8 changed files with 120 additions and 63 deletions

View File

@ -296,6 +296,8 @@ JsonReply *JsonRPCServerImplementation::Hello(const QVariantMap &params, const J
handshake.insert("cacheHashes", cacheHashes);
}
m_clientTokens[context.clientId()] = context.token();
bool badToken = false;
if (!context.token().isEmpty()) {
TokenInfo tokenInfo = NymeaCore::instance()->userManager()->tokenInfo(context.token());
@ -303,7 +305,7 @@ JsonReply *JsonRPCServerImplementation::Hello(const QVariantMap &params, const J
badToken = tokenInfo.id().isNull();
handshake.insert("authenticated", !badToken);
handshake.insert("permissionScopes", Types::scopesToStringList(userInfo.scopes()));
handshake.insert("username", userInfo.username());
handshake.insert("username", userInfo.username());
}
// If the connection is locked down already (because of a previous failed attempt) and authentication failed
@ -412,6 +414,8 @@ JsonReply *JsonRPCServerImplementation::Authenticate(const QVariantMap &params,
m_connectionLockdownTimer.start();
}
m_clientTokens[context.clientId()] = token;
return createReply(ret);
}
@ -596,11 +600,24 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac
QString targetNamespace = commandList.first();
QString method = commandList.last();
// We'll only allow setting a new token in the hello call. All other calls must match the token given in the hello
QByteArray token = m_clientTokens.value(clientId);
if (methodString == "JSONRPC.Hello") {
token = message.value("token").toByteArray();
} else if (message.value("token").toByteArray() != token) {
qCWarning(dcJsonRpc()) << "Client changed token without redoing the handshake.";
qCDebug(dcJsonRpc) << "Old token:" << token << "new token:" << message.value("token").toByteArray();
sendUnauthorizedResponse(interface, clientId, commandId, "Changing the user (token) requires a new handshake. Call JSONRPC.Hello.");
interface->terminateClientConnection(clientId);
qCWarning(dcJsonRpc()) << "Staring connection lockdown timer";
m_connectionLockdownTimer.start();
return;
}
// check if authentication is required for this transport
if (interface->configuration().authenticationEnabled) {
QByteArray token = message.value("token").toByteArray();
QStringList authExemptMethodsNoUser = {"JSONRPC.Introspect", "JSONRPC.Hello", "JSONRPC.RequestPushButtonAuth", "JSONRPC.CreateUser"};
QStringList authExemptMethodsWithUser = {"JSONRPC.Introspect", "JSONRPC.Hello", "JSONRPC.Authenticate", "JSONRPC.RequestPushButtonAuth"};
if (interface->configuration().authenticationEnabled) {
QStringList authExemptMethodsNoUser = {"JSONRPC.Hello", "JSONRPC.RequestPushButtonAuth", "JSONRPC.CreateUser"};
QStringList authExemptMethodsWithUser = {"JSONRPC.Hello", "JSONRPC.Authenticate", "JSONRPC.RequestPushButtonAuth"};
// if there is no user in the system yet, let's fail unless this is a special method for authentication itself
if (NymeaCore::instance()->userManager()->initRequired()) {
if (!authExemptMethodsNoUser.contains(methodString) && (token.isEmpty() || !NymeaCore::instance()->userManager()->verifyToken(token))) {
@ -677,7 +694,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac
}
JsonContext callContext(clientId, m_clientLocales.value(clientId));
callContext.setToken(message.value("token").toByteArray());
callContext.setToken(token);
qCDebug(dcJsonRpc()) << "Invoking method" << targetNamespace + '.' + method << "from client" << clientId;
@ -833,6 +850,7 @@ void JsonRPCServerImplementation::onPushButtonAuthFinished(int transactionId, bo
params.insert("success", success);
if (success) {
params.insert("token", token);
m_clientTokens[clientId] = token;
}
emit PushButtonAuthFinished(clientId, params);
@ -981,6 +999,7 @@ void JsonRPCServerImplementation::clientDisconnected(const QUuid &clientId)
m_clientNotifications.remove(clientId);
m_clientBuffers.remove(clientId);
m_clientLocales.remove(clientId);
m_clientTokens.remove(clientId);
if (m_pushButtonTransactions.values().contains(clientId)) {
NymeaCore::instance()->userManager()->cancelPushButtonAuth(m_pushButtonTransactions.key(clientId));
}

View File

@ -113,6 +113,7 @@ private:
QHash<QUuid, QByteArray> m_clientBuffers;
QHash<QUuid, QStringList> m_clientNotifications;
QHash<QUuid, QLocale> m_clientLocales;
QHash<QUuid, QByteArray> m_clientTokens;
QHash<int, QUuid> m_pushButtonTransactions;
QHash<QUuid, QTimer*> m_newConnectionWaitTimers;

View File

@ -164,6 +164,7 @@ UserManager::UserError UserManager::createUser(const QString &username, const QS
QSqlQuery checkForDuplicateUserQuery(m_db);
checkForDuplicateUserQuery.prepare("SELECT * FROM users WHERE lower(username) = ?;");
// Note: We're using toLower() on the username mainly for the reason that in old versions the username used to be an email address
checkForDuplicateUserQuery.addBindValue(username.toLower());
checkForDuplicateUserQuery.exec();
if (checkForDuplicateUserQuery.first()) {

View File

@ -248,20 +248,10 @@ void TestJSONRPC::testInitialSetup()
QVERIFY(spy.isValid());
QSignalSpy disconnectedSpy(m_mockTcpServer, &MockTcpServer::clientDisconnected);
// Introspect call should work in any case
qCDebug(dcTests()) << "Calling Introspect, expecting success";
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Introspect\"}\n");
if (spy.count() == 0) {
spy.wait();
}
QVERIFY(spy.count() == 1);
QJsonDocument jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
QVariantMap response = jsonDoc.toVariant().toMap();
qCDebug(dcTests()) << "Result:" << response.value("status").toString() << response.value("error").toString();
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
QJsonDocument jsonDoc;
QVariantMap response;
// Hello call should work in any case too
// Hello call should work in any case
spy.clear();
qCDebug(dcTests()) << "Calling Hello, expecting success";
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Hello\"}\n");
@ -335,10 +325,10 @@ void TestJSONRPC::testInitialSetup()
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
QCOMPARE(NymeaCore::instance()->userManager()->users().count(), 0);
// Now lets play by the rules (with an uppercase email)
// Now lets play by the rules (with an uppercase username)
spy.clear();
qCDebug(dcTests()) << "Calling CreateUser, expecting success";
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.CreateUser\", \"params\": {\"username\": \"Dummy@guh.io\", \"password\": \"DummyPW1!\"}}\n");
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.CreateUser\", \"params\": {\"username\": \"Dummy\", \"password\": \"DummyPW1!\"}}\n");
if (spy.count() == 0) {
spy.wait();
}
@ -396,7 +386,7 @@ void TestJSONRPC::testInitialSetup()
// Now lets authenticate with a wrong user
spy.clear();
qCDebug(dcTests()) << "Calling Authenticate, expecting failure (bad user)";
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"Dummy@wrong.domain\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase\"}}\n");
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"Dummy-wrong\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase\"}}\n");
if (spy.count() == 0) {
spy.wait();
}
@ -413,7 +403,7 @@ void TestJSONRPC::testInitialSetup()
spy.clear();
disconnectedSpy.clear();
qCDebug(dcTests()) << "Calling Authenticate, expecting failure (bad password)";
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"Dummy@guh.io\", \"password\": \"wrongpw\", \"deviceName\": \"testcase\"}}\n");
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"Dummy\", \"password\": \"wrongpw\", \"deviceName\": \"testcase\"}}\n");
if (spy.count() == 0) {
spy.wait();
}
@ -439,10 +429,10 @@ void TestJSONRPC::testInitialSetup()
}
QVERIFY(spy.count() == 1);
// Now lets authenticate for real (but intentionally use a lowercase email here, should still work)
// Now lets authenticate for real (but intentionally use a lowercase username here, should still work)
spy.clear();
qCDebug(dcTests()) << "Calling Authenticate, expecting success";
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"dummy@guh.io\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase\"}}\n");
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"dummy\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase\"}}\n");
if (spy.count() == 0) {
spy.wait();
}
@ -491,11 +481,12 @@ void TestJSONRPC::testRevokeToken()
QVariantList tokenList = response.value("params").toMap().value("tokenInfoList").toList();
QCOMPARE(tokenList.count(), 1);
QUuid oldTokenId = tokenList.first().toMap().value("id").toUuid();
qCDebug(dcTests()) << "have tokens:" << tokenList;
// Authenticate and create a new token
spy.clear();
qCDebug(dcTests()) << "Calling Authenticate with valid credentials" ;
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"dummy@guh.io\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase\"}}\n");
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"token\": \"" + m_apiToken + "\", \"method\": \"JSONRPC.Authenticate\", \"params\": {\"username\": \"dummy\", \"password\": \"DummyPW1!\", \"deviceName\": \"testcase-revoke-token\"}}\n");
if (spy.count() == 0) {
spy.wait();
}
@ -504,12 +495,15 @@ void TestJSONRPC::testRevokeToken()
response = jsonDoc.toVariant().toMap();
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
QCOMPARE(response.value("params").toMap().value("success").toBool(), true);
QByteArray newToken = response.value("params").toMap().value("token").toByteArray();
QVERIFY(!newToken.isEmpty());
// After an authenticate call, we need to continue with the new token
QByteArray oldToken = m_apiToken;
m_apiToken = response.value("params").toMap().value("token").toByteArray();
QVERIFY(!m_apiToken.isEmpty());
// Now do a Version call with the new token and it should work
spy.clear();
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"token\": \"" + newToken + "\", \"method\": \"JSONRPC.Version\"}\n");
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"token\": \"" + m_apiToken + "\", \"method\": \"JSONRPC.Version\"}\n");
if (spy.count() == 0) {
spy.wait();
}
@ -519,7 +513,7 @@ void TestJSONRPC::testRevokeToken()
qCDebug(dcTests()) << "Calling Version with valid token:" << response.value("status").toString() << response.value("error").toString();
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
// Now get all the tokens using the old token
// Now get all the tokens
spy.clear();
qCDebug(dcTests()) << "Calling Tokens";
m_mockTcpServer->injectData(m_clientId, "{\"id\": 123, \"token\": \"" + m_apiToken + "\", \"method\": \"Users.GetTokens\"}\n");
@ -531,21 +525,14 @@ void TestJSONRPC::testRevokeToken()
response = jsonDoc.toVariant().toMap();
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
tokenList = response.value("params").toMap().value("tokenInfoList").toList();
qCDebug(dcTests()) << "have tokens:" << tokenList;
QCOMPARE(tokenList.count(), 2);
// find the new token
QUuid newTokenId;
foreach (const QVariant &tokenInfo, tokenList) {
if (tokenInfo.toMap().value("id").toUuid() != oldTokenId) {
newTokenId = tokenInfo.toMap().value("id").toUuid();
break;
}
}
// Revoke the new token
// Revoke the old token
spy.clear();
qCDebug(dcTests()) << "Calling RemoveToken";
m_mockTcpServer->injectData(m_clientId, "{\"id\": 123, \"token\": \"" + m_apiToken + "\", \"method\": \"Users.RemoveToken\", \"params\": {\"tokenId\": \"" + newTokenId.toByteArray() + "\"}}\n");
m_mockTcpServer->injectData(m_clientId, "{\"id\": 123, \"token\": \"" + m_apiToken + "\", \"method\": \"Users.RemoveToken\", \"params\": {\"tokenId\": \"" + oldTokenId.toByteArray() + "\"}}\n");
if (spy.count() == 0) {
spy.wait();
}
@ -554,11 +541,40 @@ void TestJSONRPC::testRevokeToken()
response = jsonDoc.toVariant().toMap();
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
// Do a call with the now removed token, it should be forbidden
// Get all the tokens and see if it's down by one.
spy.clear();
qCDebug(dcTests()) << "Calling Tokens";
m_mockTcpServer->injectData(m_clientId, "{\"id\": 123, \"token\": \"" + m_apiToken + "\", \"method\": \"Users.GetTokens\"}\n");
if (spy.count() == 0) {
spy.wait();
}
QVERIFY(spy.count() == 1);
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
response = jsonDoc.toVariant().toMap();
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
tokenList = response.value("params").toMap().value("tokenInfoList").toList();
qCDebug(dcTests()) << "have tokens:" << tokenList;
QCOMPARE(tokenList.count(), 1);
// Do a handshake with the old removed token, it should work, but telling us the token is invalid
spy.clear();
disconnectedSpy.clear();
qCDebug(dcTests()) << "Calling Hello with now removed token";
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"token\": \"" + oldToken + "\", \"method\": \"JSONRPC.Hello\"}\n");
if (spy.count() == 0) {
spy.wait();
}
QVERIFY(spy.count() == 1);
jsonDoc = QJsonDocument::fromJson(spy.first().at(1).toByteArray());
response = jsonDoc.toVariant().toMap();
QCOMPARE(response.value("status").toString(), QStringLiteral("success"));
QCOMPARE(response.value("params").toMap().value("authenticated").toBool(), false);
// Do a version call with the old removed token, it should be forbidden
spy.clear();
disconnectedSpy.clear();
qCDebug(dcTests()) << "Calling Version with now removed token";
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"token\": \"" + newToken + "\", \"method\": \"JSONRPC.Version\"}\n");
m_mockTcpServer->injectData(m_clientId, "{\"id\": 555, \"token\": \"" + oldToken + "\", \"method\": \"JSONRPC.Version\"}\n");
if (spy.count() == 0) {
spy.wait();
}
@ -584,16 +600,16 @@ void TestJSONRPC::testBasicCall_data()
QTest::addColumn<bool>("idValid");
QTest::addColumn<bool>("valid");
QTest::newRow("valid call 1") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Introspect\"}") << true << true;
QTest::newRow("valid call 2") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Introspect\"}\n") << true << true;
QTest::newRow("valid call 3") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Introspect\"}\n\n\n\n") << true << true;
QTest::newRow("missing id") << QByteArray("{\"method\":\"JSONRPC.Introspect\"}\n") << false << false;
QTest::newRow("missing method") << QByteArray("{\"id\":42}\n") << true << false;
QTest::newRow("borked") << QByteArray("{\"id\":42, \"method\":\"JSO}\n") << false << false;
QTest::newRow("valid call 1") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Introspect\", \"token\": \"" + m_apiToken + "\"}") << true << true;
QTest::newRow("valid call 2") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Introspect\", \"token\": \"" + m_apiToken + "\"}\n") << true << true;
QTest::newRow("valid call 3") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Introspect\", \"token\": \"" + m_apiToken + "\"}\n\n\n\n") << true << true;
QTest::newRow("missing id") << QByteArray("{\"method\":\"JSONRPC.Introspect\", \"token\": \"" + m_apiToken + "\"}\n") << false << false;
QTest::newRow("missing method") << QByteArray("{\"id\":42, \"token\": \"" + m_apiToken + "\"}\n") << true << false;
QTest::newRow("borked") << QByteArray("{\"id\":42,, \"token\": \"" + m_apiToken + "\" \"method\":\"JSO}\n") << false << false;
QTest::newRow("invalid function") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Foobar\", \"token\": \"" + m_apiToken + "\"}\n") << true << false;
QTest::newRow("invalid namespace") << QByteArray("{\"id\":42, \"method\":\"FOO.Introspect\", \"token\": \"" + m_apiToken + "\"}\n") << true << false;
QTest::newRow("missing dot") << QByteArray("{\"id\":42, \"method\":\"JSONRPCIntrospect\", \"token\": \"" + m_apiToken + "\"}\n") << true << false;
QTest::newRow("invalid params") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Introspect\", \"params\":{\"törööö\":\"chooo-chooo\"}}\n") << true << false;
QTest::newRow("invalid params") << QByteArray("{\"id\":42, \"method\":\"JSONRPC.Introspect\", \"token\": \"" + m_apiToken + "\", \"params\":{\"törööö\":\"chooo-chooo\"}}\n") << true << false;
}
void TestJSONRPC::testBasicCall()
@ -980,7 +996,7 @@ void TestJSONRPC::testPushButtonAuth()
int transactionId = response.toMap().value("params").toMap().value("transactionId").toInt();
// Setup connection to mock client
QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
QSignalSpy clientSpy(m_mockTcpServer, &MockTcpServer::outgoingData);
pushButtonAgent.sendButtonPressed();
@ -989,8 +1005,14 @@ void TestJSONRPC::testPushButtonAuth()
QCOMPARE(rsp.value("params").toMap().value("transactionId").toInt(), transactionId);
QVERIFY2(!rsp.value("params").toMap().value("token").toByteArray().isEmpty(), "Token not in push button auth notification");
}
m_apiToken = rsp.value("params").toMap().value("token").toByteArray();
qCDebug(dcTests()) << "Invoking Version";
// Test a regular call to verify we're actually authenticated
response = injectAndWait("JSONRPC.Version");
QVERIFY2(response.toMap().value("status").toString() == "success", "JSONRPC.Version call failed after push button auth!");
}
void TestJSONRPC::testPushButtonAuthInterrupt()
@ -1024,7 +1046,7 @@ void TestJSONRPC::testPushButtonAuthInterrupt()
clientSpy.clear();
params.clear();
params.insert("deviceName", "mallory");
response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, malloryId);
response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, malloryId, "");
QCOMPARE(response.toMap().value("params").toMap().value("success").toBool(), true);
int transactionId2 = response.toMap().value("params").toMap().value("transactionId").toInt();
@ -1097,6 +1119,7 @@ void TestJSONRPC::testPushButtonAuthInterrupt()
QCOMPARE(notification.value("params").toMap().value("transactionId").toInt(), transactionId3);
QCOMPARE(notification.value("params").toMap().value("success").toBool(), true);
QVERIFY2(!notification.value("params").toMap().value("token").toByteArray().isEmpty(), "Token is empty while it shouldn't be");
}
void TestJSONRPC::testPushButtonAuthConnectionDrop()
@ -1116,7 +1139,7 @@ void TestJSONRPC::testPushButtonAuthConnectionDrop()
// request push button auth for client 1 (alice) and check for OK reply
QVariantMap params;
params.insert("deviceName", "alice");
QVariant response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, aliceId);
QVariant response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, aliceId, "");
QCOMPARE(response.toMap().value("params").toMap().value("success").toBool(), true);
// Disconnect alice
@ -1133,7 +1156,7 @@ void TestJSONRPC::testPushButtonAuthConnectionDrop()
// request push button auth for client 2 (bob) and check for OK reply
params.clear();
params.insert("deviceName", "bob");
response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, bobId);
response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, bobId, "");
QCOMPARE(response.toMap().value("params").toMap().value("success").toBool(), true);
int transactionId = response.toMap().value("params").toMap().value("transactionId").toInt();
@ -1154,7 +1177,6 @@ void TestJSONRPC::testPushButtonAuthConnectionDrop()
QCOMPARE(notification.value("params").toMap().value("transactionId").toInt(), transactionId);
QCOMPARE(notification.value("params").toMap().value("success").toBool(), true);
QVERIFY2(!notification.value("params").toMap().value("token").toByteArray().isEmpty(), "Token is empty while it shouldn't be");
}
void TestJSONRPC::testInitialSetupWithPushButtonAuth()
@ -1194,7 +1216,7 @@ void TestJSONRPC::testInitialSetupWithPushButtonAuth()
QVariantMap params;
params.insert("deviceName", "alice");
response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, aliceId);
response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, aliceId, "");
QCOMPARE(response.toMap().value("params").toMap().value("success").toBool(), true);
int transactionId = response.toMap().value("params").toMap().value("transactionId").toInt();

View File

@ -197,6 +197,8 @@ void TestUsermanager::createUser()
void TestUsermanager::authenticate()
{
m_apiToken.clear();
injectAndWait("JSONRPC.Hello");
createUser();
QVariantMap params;
@ -237,6 +239,13 @@ void TestUsermanager::authenticatePushButton()
QCOMPARE(rsp.value("params").toMap().value("transactionId").toInt(), transactionId);
QVERIFY2(!rsp.value("params").toMap().value("token").toByteArray().isEmpty(), "Token not in push button auth notification");
m_apiToken = rsp.value("params").toMap().value("token").toByteArray();
qCDebug(dcTests()) << "Invoking Version";
// Test a regular call to verify we're actually authenticated
response = injectAndWait("JSONRPC.Version");
QVERIFY2(response.toMap().value("status").toString() == "success", "JSONRPC.Version call failed after push button auth!");
}
void TestUsermanager::authenticatePushButtonAuthInterrupt()
@ -269,7 +278,7 @@ void TestUsermanager::authenticatePushButtonAuthInterrupt()
clientSpy.clear();
params.clear();
params.insert("deviceName", "mallory");
response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, malloryId);
response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, malloryId, "");
QCOMPARE(response.toMap().value("params").toMap().value("success").toBool(), true);
int transactionId2 = response.toMap().value("params").toMap().value("transactionId").toInt();
@ -361,7 +370,7 @@ void TestUsermanager::authenticatePushButtonAuthConnectionDrop()
// request push button auth for client 1 (alice) and check for OK reply
QVariantMap params;
params.insert("deviceName", "alice");
QVariant response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, aliceId);
QVariant response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, aliceId, "");
QCOMPARE(response.toMap().value("params").toMap().value("success").toBool(), true);
// Disconnect alice
@ -378,7 +387,7 @@ void TestUsermanager::authenticatePushButtonAuthConnectionDrop()
// request push button auth for client 2 (bob) and check for OK reply
params.clear();
params.insert("deviceName", "bob");
response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, bobId);
response = injectAndWait("JSONRPC.RequestPushButtonAuth", params, bobId, "");
QCOMPARE(response.toMap().value("params").toMap().value("success").toBool(), true);
int transactionId = response.toMap().value("params").toMap().value("transactionId").toInt();

View File

@ -83,7 +83,7 @@ void TestWebSocketServer::initTestCase()
config.address = "127.0.0.1";
config.port = 4444;
config.sslEnabled = true;
config.authenticationEnabled = true;
config.authenticationEnabled = false;
NymeaCore::instance()->configuration()->setWebSocketServerConfiguration(config);
}

View File

@ -87,6 +87,11 @@ void NymeaTestBase::initTestCase(const QString &loggingRules)
qApp->processEvents();
qCDebug(dcTests()) << "Nymea core instance initialized. Creating dummy user.";
foreach (const UserInfo &userInfo, NymeaCore::instance()->userManager()->users()) {
NymeaCore::instance()->userManager()->removeUser(userInfo.username());
}
NymeaCore::instance()->userManager()->removeUser("");
// Yes, we're intentionally mixing upper/lower case email here... username should not be case sensitive
NymeaCore::instance()->userManager()->removeUser("dummy");
NymeaCore::instance()->userManager()->createUser("dummy", "DummyPW1!", "dummy@guh.io", "Dummy", Types::PermissionScopeAdmin);
@ -128,13 +133,13 @@ void NymeaTestBase::cleanup()
}
}
QVariant NymeaTestBase::injectAndWait(const QString &method, const QVariantMap &params, const QUuid &clientId)
QVariant NymeaTestBase::injectAndWait(const QString &method, const QVariantMap &params, const QUuid &clientId, const QByteArray &tokenOverride)
{
QVariantMap call;
call.insert("id", m_commandId);
call.insert("method", method);
call.insert("params", params);
call.insert("token", m_apiToken);
call.insert("token", tokenOverride == "default" ? m_apiToken : tokenOverride);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(call);
QSignalSpy spy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));

View File

@ -56,7 +56,7 @@ protected slots:
void cleanup();
protected:
QVariant injectAndWait(const QString &method, const QVariantMap &params = QVariantMap(), const QUuid &clientId = QUuid());
QVariant injectAndWait(const QString &method, const QVariantMap &params = QVariantMap(), const QUuid &clientId = QUuid(), const QByteArray &tokenOverride = "default");
QVariant checkNotification(const QSignalSpy &spy, const QString &notification);
QVariantList checkNotifications(const QSignalSpy &spy, const QString &notification);