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; 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; bool success = true;
#ifdef HAVE_MQTT #ifdef HAVE_MQTT
DataHandler* handler = mqtthandler_register(busHandler, messages); DataHandler* handler = mqtthandler_register(userInfo, busHandler, messages);
if (handler) { if (handler) {
handlers.push_back(handler); handlers.push_back(handler);
} else { } else {
@@ -64,7 +65,9 @@ bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list<Dat
} }
void DataSink::notifyUpdate(Message* message) { void DataSink::notifyUpdate(Message* message) {
m_updatedMessages[message]++; if (message && message->hasLevel(m_levels)) {
m_updatedMessages[message]++;
}
} }
} // namespace ebusd } // namespace ebusd
+47 -2
View File
@@ -22,6 +22,7 @@
#include <argp.h> #include <argp.h>
#include <map> #include <map>
#include <list> #include <list>
#include <string>
#include "ebusd/bushandler.h" #include "ebusd/bushandler.h"
#include "lib/ebus/message.h" #include "lib/ebus/message.h"
@@ -36,6 +37,7 @@ namespace ebusd {
using std::list; using std::list;
using std::map; using std::map;
class UserInfo;
class DataHandler; class DataHandler;
/** /**
@@ -46,12 +48,48 @@ const struct argp_child* datahandler_getargs();
/** /**
* Registration function that is called once during initialization. * Registration function that is called once during initialization.
* @param userInfo the @a UserInfo instance.
* @param busHandler the @a BusHandler instance. * @param busHandler the @a BusHandler instance.
* @param messages the @a MessageMap instance. * @param messages the @a MessageMap instance.
* @param handlers the @a list to which new @a DataHandler instances shall be added. * @param handlers the @a list to which new @a DataHandler instances shall be added.
* @return true if registration was successful. * @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: public:
/** /**
* Constructor. * 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. * Destructor.
@@ -114,6 +156,9 @@ class DataSink : virtual public DataHandler {
protected: protected:
/** the allowed access levels. */
string m_levels;
/** a map of updated @p Message instances. */ /** a map of updated @p Message instances. */
map<Message*, int> m_updatedMessages; map<Message*, int> m_updatedMessages;
}; };
+16 -19
View File
@@ -165,8 +165,8 @@ const struct argp_child* mqtthandler_getargs() {
return &g_mqtt_argp_child; return &g_mqtt_argp_child;
} }
DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages) { DataHandler* mqtthandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages) {
return new MqttHandler(busHandler, messages); return new MqttHandler(userInfo, busHandler, messages);
} }
/** the known topic column names. */ /** the known topic column names. */
@@ -177,7 +177,7 @@ static const char* columnNames[] = {
}; };
/** the known topic column IDs. */ /** the known topic column IDs. */
static const size_t columnIds[] = { static const column_t columnIds[] = {
COLUMN_CIRCUIT, COLUMN_CIRCUIT,
COLUMN_NAME, COLUMN_NAME,
COLUMN_FIELDS, 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. * @param cols the @a vector to which the column parts shall be added.
* @return true on success, false on malformed topic template. * @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 lastpos = 0;
size_t end = topic.length(); size_t end = topic.length();
vector<string> columns; vector<string> columns;
for (size_t pos=topic.find('%', lastpos); pos != string::npos; ) { for (size_t pos=topic.find('%', lastpos); pos != string::npos; ) {
size_t col = columnCount; size_t idx = columnCount;
size_t len = 0; size_t len = 0;
for (size_t i = 0; i < columnCount; i++) { for (size_t i = 0; i < columnCount; i++) {
len = strlen(columnNames[i]); len = strlen(columnNames[i]);
if (topic.substr(pos+1, len) == columnNames[i]) { if (topic.substr(pos+1, len) == columnNames[i]) {
col = columnIds[i]; idx = i;
break; break;
} }
} }
if (col == columnCount) { if (idx== columnCount) {
return false; 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) { if (*it == col) {
return false; // duplicate column return false; // duplicate column
} }
@@ -259,8 +260,8 @@ void on_connect(
} }
MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages) MqttHandler::MqttHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages)
: DataSink(), DataSource(busHandler), Thread(), m_messages(messages), m_connected(false) { : DataSink(userInfo, "mqtt"), DataSource(busHandler), Thread(), m_messages(messages), m_connected(false) {
bool enabled = g_port != 0; bool enabled = g_port != 0;
m_publishByField = false; m_publishByField = false;
m_mosquitto = NULL; m_mosquitto = NULL;
@@ -396,17 +397,16 @@ void MqttHandler::notifyTopic(string topic, string data) {
if (pos == string::npos) { if (pos == string::npos) {
return; return;
} }
string suffix = topic.substr(pos+1); string direction = topic.substr(pos+1);
bool isWrite = false; bool isWrite = false;
if (suffix.empty()) { if (direction.empty()) {
return; return;
} }
string direction = suffix.substr(0, 3);
isWrite = direction == "set"; isWrite = direction == "set";
if (!isWrite && direction != "get") { if (!isWrite && direction != "get") {
return; return;
} }
suffix = suffix.substr(3); // security level
logOtherDebug("mqtt", "received topic %s", topic.c_str(), data.c_str()); logOtherDebug("mqtt", "received topic %s", topic.c_str(), data.c_str());
string remain = topic.substr(0, pos); string remain = topic.substr(0, pos);
size_t last = 0; size_t last = 0;
@@ -457,12 +457,9 @@ void MqttHandler::notifyTopic(string topic, string data) {
return; return;
} }
logOtherInfo("mqtt", "received topic for %s %s", circuit.c_str(), name.c_str()); logOtherInfo("mqtt", "received topic for %s %s", circuit.c_str(), name.c_str());
if (suffix.length() > 0) { Message* message = m_messages->find(circuit, name, m_levels, isWrite);
circuit += "#"+suffix;
}
Message* message = m_messages->find(circuit, name, isWrite);
if (message == NULL) { if (message == NULL) {
message = m_messages->find(circuit, name, isWrite, true); message = m_messages->find(circuit, name, m_levels, isWrite, true);
} }
if (message == NULL) { if (message == NULL) {
logOtherError("mqtt", "%s message %s %s not found", isWrite?"write":"read", circuit.c_str(), name.c_str()); 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. * Registration function that is called once during initialization.
* @param userInfo the @a UserInfo instance.
* @param busHandler the @a BusHandler instance. * @param busHandler the @a BusHandler instance.
* @param messages the @a MessageMap instance. * @param messages the @a MessageMap instance.
* @return the create @a DataHandler, or NULL on error. * @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. * The main class supporting MQTT data handling.
@@ -58,10 +59,11 @@ class MqttHandler : public DataSink, public DataSource, public Thread {
public: public:
/** /**
* Constructor. * Constructor.
* @param userInfo the @a UserInfo instance.
* @param busHandler the @a BusHandler instance. * @param busHandler the @a BusHandler instance.
* @param messages the @a MessageMap instance. * @param messages the @a MessageMap instance.
*/ */
MqttHandler(BusHandler* busHandler, MessageMap* messages); MqttHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages);
/** /**
* Destructor. * Destructor.
@@ -120,7 +122,7 @@ class MqttHandler : public DataSink, public DataSource, public Thread {
vector<string> m_topicStrs; vector<string> m_topicStrs;
/** the MQTT topic column parts. */ /** the MQTT topic column parts. */
vector<size_t> m_topicCols; vector<column_t> m_topicCols;
/** the global topic prefix. */ /** the global topic prefix. */
string m_globalTopic; string m_globalTopic;