Skip to content

Commit d947e7e

Browse files
committed
Allow publication of $SYS topics to be seen by plugin
The plugin can't deny it though.
1 parent ad4722c commit d947e7e

File tree

6 files changed

+51
-14
lines changed

6 files changed

+51
-14
lines changed

FlashMQTests/tst_maintests.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,30 @@ void MainTests::test_acl_patterns_clientid()
481481
QCOMPARE(aclTree.findPermission(splitToVector("d/clientid_one/f/A/B", '/'), AclGrant::Read, "foo", "clientid_one"), AuthResult::success);
482482
}
483483

484+
/**
485+
* @brief MainTests::test_loading_acl_file was created because assertions in it failed when publishing $SYS topics were passed through the ACL
486+
* layer. That's why it seemingly doesn't do anything.
487+
*/
488+
void MainTests::test_loading_acl_file()
489+
{
490+
ConfFileTemp aclFile;
491+
aclFile.writeLine("topic readwrite one/two");
492+
aclFile.closeFile();
493+
494+
ConfFileTemp confFile;
495+
confFile.writeLine("mosquitto_acl_file " + aclFile.getFilePath());
496+
confFile.closeFile();
497+
498+
std::vector<std::string> args {"--config-file", confFile.getFilePath()};
499+
500+
cleanup();
501+
init(args);
502+
503+
usleep(1000000);
504+
505+
QVERIFY(true);
506+
}
507+
484508
#ifndef FMQ_NO_SSE
485509
void MainTests::test_sse_split()
486510
{

FlashMQTests/tst_maintests.h

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ private slots:
9292
void test_acl_tree2();
9393
void test_acl_patterns_username();
9494
void test_acl_patterns_clientid();
95+
void test_loading_acl_file();
9596

9697
void test_validUtf8Generic();
9798
#ifndef FMQ_NO_SSE

acltree.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,9 @@ void AclTree::findPermissionRecursive(std::vector<std::string>::const_iterator c
236236
AuthResult AclTree::findPermission(const std::vector<std::string> &subtopicsPublish, AclGrant access, const std::string &username, const std::string &clientid)
237237
{
238238
assert(access == AclGrant::Read || access == AclGrant::Write);
239-
assert(!clientid.empty());
239+
240+
// Empty clientid is when FlashMQ itself publishes, and that is fine for 'write'. on 'read', it should still never happen.
241+
assert(!(clientid.empty() && access == AclGrant::Read ));
240242

241243
collectedPermissions.clear();
242244

plugin.cpp

+9-4
Original file line numberDiff line numberDiff line change
@@ -268,15 +268,20 @@ void Authentication::securityCleanup(bool reloading)
268268
* @brief Authentication::aclCheck performs a write ACL check on the incoming publish.
269269
* @param publishData
270270
* @return
271+
*
272+
* Internal publishes write (publish) access is always allowed (it makes little sense that a plugin would have to explicitly allow
273+
* those), but they are passed through the plugin, so you can inspect them. The read access can still be rejected by a plugin.
271274
*/
272275
AuthResult Authentication::aclCheck(Publish &publishData, std::string_view payload, AclAccess access)
273276
{
277+
AuthResult result = aclCheck(publishData.client_id, publishData.username, publishData.topic, publishData.getSubtopics(), payload, access, publishData.qos,
278+
publishData.retain, publishData.getUserProperties());
279+
274280
// Anonymous publishes come from FlashMQ internally, like SYS topics. We need to allow them.
275-
if (publishData.client_id.empty())
276-
return AuthResult::success;
281+
if (access == AclAccess::write && publishData.client_id.empty())
282+
result = AuthResult::success;
277283

278-
return aclCheck(publishData.client_id, publishData.username, publishData.topic, publishData.getSubtopics(), payload, access, publishData.qos,
279-
publishData.retain, publishData.getUserProperties());
284+
return result;
280285
}
281286

282287
AuthResult Authentication::aclCheck(const std::string &clientid, const std::string &username, const std::string &topic, const std::vector<std::string> &subtopics,

threaddata.cpp

+13-9
Original file line numberDiff line numberDiff line change
@@ -478,20 +478,15 @@ void ThreadData::publishStatsOnDollarTopic(std::vector<std::shared_ptr<ThreadDat
478478
for (auto &pair : globalStats->getExtras())
479479
{
480480
Publish p(pair.first, pair.second, 0);
481-
PublishCopyFactory factory(&p);
482-
std::shared_ptr<SubscriptionStore> subscriptionStore = MainApp::getMainApp()->getSubscriptionStore();
483-
subscriptionStore->queuePacketAtSubscribers(factory, "", true);
481+
publishWithAcl(p);
484482
}
485483
}
486484

487485
void ThreadData::publishStat(const std::string &topic, uint64_t n)
488486
{
489487
const std::string payload = std::to_string(n);
490488
Publish p(topic, payload, 0);
491-
PublishCopyFactory factory(&p);
492-
std::shared_ptr<SubscriptionStore> subscriptionStore = MainApp::getMainApp()->getSubscriptionStore();
493-
subscriptionStore->queuePacketAtSubscribers(factory, "", true);
494-
subscriptionStore->setRetainedMessage(p, factory.getSubtopics());
489+
publishWithAcl(p, true);
495490
}
496491

497492
void ThreadData::publishBridgeState(std::shared_ptr<BridgeState> bridge, bool connected)
@@ -509,10 +504,19 @@ void ThreadData::publishBridgeState(std::shared_ptr<BridgeState> bridge, bool co
509504
globalStats->setExtra(topic, payload);
510505

511506
Publish p(topic, payload, 0);
512-
PublishCopyFactory factory(&p);
507+
publishWithAcl(p, true);
508+
}
509+
510+
void ThreadData::publishWithAcl(Publish &pub, bool setRetain)
511+
{
512+
authentication.aclCheck(pub, pub.payload, AclAccess::write);
513+
514+
PublishCopyFactory factory(&pub);
513515
std::shared_ptr<SubscriptionStore> subscriptionStore = MainApp::getMainApp()->getSubscriptionStore();
514516
subscriptionStore->queuePacketAtSubscribers(factory, "", true);
515-
subscriptionStore->setRetainedMessage(p, factory.getSubtopics());
517+
518+
if (setRetain)
519+
subscriptionStore->setRetainedMessage(pub, factory.getSubtopics());
516520
}
517521

518522
/**

threaddata.h

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class ThreadData
8989
void bridgeReconnect();
9090

9191
void removeQueuedClients();
92+
void publishWithAcl(Publish &pub, bool setRetain=false);
9293

9394
public:
9495
Settings settingsLocalCopy; // Is updated on reload, within the thread loop.

0 commit comments

Comments
 (0)