add UserInfo and limit publish/subscribe to authorized messages only

This commit is contained in:
john30
2017-02-18 11:44:41 +01:00
parent 33128f221a
commit 180a2056f4
4 changed files with 74 additions and 27 deletions
+6 -3
View File
@@ -50,10 +50,11 @@ const struct argp_child* datahandler_getargs() {
return NULL;
}
bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list<DataHandler*>& handlers) {
bool datahandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages,
list<DataHandler*>& handlers) {
bool success = true;
#ifdef HAVE_MQTT
DataHandler* handler = mqtthandler_register(busHandler, messages);
DataHandler* handler = mqtthandler_register(userInfo, busHandler, messages);
if (handler) {
handlers.push_back(handler);
} else {
@@ -64,7 +65,9 @@ bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list<Dat
}
void DataSink::notifyUpdate(Message* message) {
m_updatedMessages[message]++;
if (message && message->hasLevel(m_levels)) {
m_updatedMessages[message]++;
}
}
} // namespace ebusd
+47 -2
View File
@@ -22,6 +22,7 @@
#include <argp.h>
#include <map>
#include <list>
#include <string>
#include "ebusd/bushandler.h"
#include "lib/ebus/message.h"
@@ -36,6 +37,7 @@ namespace ebusd {
using std::list;
using std::map;
class UserInfo;
class DataHandler;
/**
@@ -46,12 +48,48 @@ const struct argp_child* datahandler_getargs();
/**
* Registration function that is called once during initialization.
* @param userInfo the @a UserInfo instance.
* @param busHandler the @a BusHandler instance.
* @param messages the @a MessageMap instance.
* @param handlers the @a list to which new @a DataHandler instances shall be added.
* @return true if registration was successful.
*/
bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list<DataHandler*>& handlers);
bool datahandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages,
list<DataHandler*>& handlers);
/**
* Helper interface for user authentication.
*/
class UserInfo {
public:
/**
* Destructor.
*/
virtual ~UserInfo() {}
/**
* Check whether the specified user exists.
* @param user the user name.
* @return whether the user exists.
*/
virtual bool hasUser(const string user) = 0; // abstract
/**
* Check whether the secret string matches the one of the specified user.
* @param user the user name.
* @param secret the secret to check.
* @return whether the secret string is valid.
*/
virtual bool checkSecret(const string user, const string secret) = 0; // abstract
/**
* Get the access levels associated with the specified user.
* @param user the user name, or empty for default levels.
* @return the access levels separated by semicolon.
*/
virtual string getLevels(const string user) = 0; // abstract
};
/**
@@ -95,8 +133,12 @@ class DataSink : virtual public DataHandler {
public:
/**
* Constructor.
* @param userInfo the @a UserInfo instance.
* @param user the user name for determining the allowed access levels (fall back to default levels).
*/
DataSink() {}
DataSink(UserInfo* userInfo, string user) {
m_levels = userInfo->getLevels(userInfo->hasUser(user) ? user : "");
}
/**
* Destructor.
@@ -114,6 +156,9 @@ class DataSink : virtual public DataHandler {
protected:
/** the allowed access levels. */
string m_levels;
/** a map of updated @p Message instances. */
map<Message*, int> m_updatedMessages;
};
+16 -19
View File
@@ -165,8 +165,8 @@ const struct argp_child* mqtthandler_getargs() {
return &g_mqtt_argp_child;
}
DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages) {
return new MqttHandler(busHandler, messages);
DataHandler* mqtthandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages) {
return new MqttHandler(userInfo, busHandler, messages);
}
/** the known topic column names. */
@@ -177,7 +177,7 @@ static const char* columnNames[] = {
};
/** the known topic column IDs. */
static const size_t columnIds[] = {
static const column_t columnIds[] = {
COLUMN_CIRCUIT,
COLUMN_NAME,
COLUMN_FIELDS,
@@ -194,24 +194,25 @@ static const size_t columnCount = sizeof(columnNames) / sizeof(char*);
* @param cols the @a vector to which the column parts shall be added.
* @return true on success, false on malformed topic template.
*/
bool parseTopic(const string topic, vector<string> &strs, vector<size_t> &cols) {
bool parseTopic(const string topic, vector<string> &strs, vector<column_t> &cols) {
size_t lastpos = 0;
size_t end = topic.length();
vector<string> columns;
for (size_t pos=topic.find('%', lastpos); pos != string::npos; ) {
size_t col = columnCount;
size_t idx = columnCount;
size_t len = 0;
for (size_t i = 0; i < columnCount; i++) {
len = strlen(columnNames[i]);
if (topic.substr(pos+1, len) == columnNames[i]) {
col = columnIds[i];
idx = i;
break;
}
}
if (col == columnCount) {
if (idx== columnCount) {
return false;
}
for (vector<size_t>::iterator it=cols.begin(); it != cols.end(); it++) {
column_t col = columnIds[idx];
for (vector<column_t>::iterator it=cols.begin(); it != cols.end(); it++) {
if (*it == col) {
return false; // duplicate column
}
@@ -259,8 +260,8 @@ void on_connect(
}
MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
: DataSink(), DataSource(busHandler), Thread(), m_messages(messages), m_connected(false) {
MqttHandler::MqttHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages)
: DataSink(userInfo, "mqtt"), DataSource(busHandler), Thread(), m_messages(messages), m_connected(false) {
bool enabled = g_port != 0;
m_publishByField = false;
m_mosquitto = NULL;
@@ -396,17 +397,16 @@ void MqttHandler::notifyTopic(string topic, string data) {
if (pos == string::npos) {
return;
}
string suffix = topic.substr(pos+1);
string direction = topic.substr(pos+1);
bool isWrite = false;
if (suffix.empty()) {
if (direction.empty()) {
return;
}
string direction = suffix.substr(0, 3);
isWrite = direction == "set";
if (!isWrite && direction != "get") {
return;
}
suffix = suffix.substr(3); // security level
logOtherDebug("mqtt", "received topic %s", topic.c_str(), data.c_str());
string remain = topic.substr(0, pos);
size_t last = 0;
@@ -457,12 +457,9 @@ void MqttHandler::notifyTopic(string topic, string data) {
return;
}
logOtherInfo("mqtt", "received topic for %s %s", circuit.c_str(), name.c_str());
if (suffix.length() > 0) {
circuit += "#"+suffix;
}
Message* message = m_messages->find(circuit, name, isWrite);
Message* message = m_messages->find(circuit, name, m_levels, isWrite);
if (message == NULL) {
message = m_messages->find(circuit, name, isWrite, true);
message = m_messages->find(circuit, name, m_levels, isWrite, true);
}
if (message == NULL) {
logOtherError("mqtt", "%s message %s %s not found", isWrite?"write":"read", circuit.c_str(), name.c_str());
+5 -3
View File
@@ -45,11 +45,12 @@ const struct argp_child* mqtthandler_getargs();
/**
* Registration function that is called once during initialization.
* @param userInfo the @a UserInfo instance.
* @param busHandler the @a BusHandler instance.
* @param messages the @a MessageMap instance.
* @return the create @a DataHandler, or NULL on error.
*/
DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages);
DataHandler* mqtthandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages);
/**
* The main class supporting MQTT data handling.
@@ -58,10 +59,11 @@ class MqttHandler : public DataSink, public DataSource, public Thread {
public:
/**
* Constructor.
* @param userInfo the @a UserInfo instance.
* @param busHandler the @a BusHandler instance.
* @param messages the @a MessageMap instance.
*/
MqttHandler(BusHandler* busHandler, MessageMap* messages);
MqttHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages);
/**
* Destructor.
@@ -120,7 +122,7 @@ class MqttHandler : public DataSink, public DataSource, public Thread {
vector<string> m_topicStrs;
/** the MQTT topic column parts. */
vector<size_t> m_topicCols;
vector<column_t> m_topicCols;
/** the global topic prefix. */
string m_globalTopic;