Commit e35674b1 authored by Micha Mueller's avatar Micha Mueller
Browse files

Make authentication tokens for REST API configurable

parent 3c03666e
......@@ -14,14 +14,14 @@ restAPI {
privateKey ../deps/openssl-1.0.2l/certs/demo/ca-cert.pem
dhFile ../deps/openssl-1.0.2l/crypto/dh/dh2048.pem
; authkey qwertz {
; PUT
; GET
; }
;
; authkey yxcvbn {
; GET
; }
authkey qwertz {
PUTReq
GETReq
}
authkey yxcvbn {
GETReq
}
}
plugins {
......
......@@ -116,6 +116,8 @@ bool Configuration::readGlobal() {
_global.restAPISettings.privateKey = global.second.data();
} else if (boost::iequals(global.first, "dhFile")) {
_global.restAPISettings.dhFile = global.second.data();
} else if (boost::iequals(global.first, "authkey")) {
//Avoid unnecessary "Value not recognized" message
} else {
LOG(warning) << " Value \"" << global.first << "\" not recognized. Omitting";
}
......@@ -132,7 +134,7 @@ bool Configuration::read() {
try {
boost::property_tree::read_info(globalConfig, cfg);
} catch (boost::property_tree::info_parser_error& e) {
LOG(fatal) << "global.conf not found! Please make sure the config-path is correct.";
LOG(error) << "Error when reading plugins from global.conf: " << e.what();
return false;
}
......@@ -240,6 +242,56 @@ bool Configuration::read() {
return true;
}
bool Configuration::readAuthkeys(HttpsServer& server) {
//open file
std::string globalConfig = _cfgFilePath;
globalConfig.append("global.conf");
boost::property_tree::iptree cfg;
//parse to property_tree
try {
boost::property_tree::read_info(globalConfig, cfg);
} catch (boost::property_tree::info_parser_error& e) {
LOG(error) << "Error when reading authkeys from global.conf: " << e.what();
return false;
}
//read authkeys
BOOST_FOREACH(boost::property_tree::iptree::value_type &global, cfg.get_child("restAPI")) {
if (boost::iequals(global.first, "authkey")) {
#ifdef DEBUG
LOG(info) << "Authentication token \"" << global.second.data() << "\"";
#endif
std::bitset<NUM_PERMISSIONS> permissions;
BOOST_FOREACH(boost::property_tree::iptree::value_type &perm, global.second) {
if (boost::iequals(perm.first, "GETReq")) {
#ifdef DEBUG
LOG(info) << " Permission \"GETReq\"";
#endif
permissions[GETReq] = true;
} else if (boost::iequals(perm.first, "PUTReq")) {
#ifdef DEBUG
LOG(info) << " Permission \"PUTReq\"";
#endif
permissions[PUTReq] = true;
} else {
#ifdef DEBUG
LOG(warning) << "Permission \"" << perm.first << "\" not recognized. Omitting";
#endif
}
}
if (!server.addAuthkey(authkeyMap_t::value_type(global.second.data(), permissions))) {
#ifdef DEBUG
LOG(warning) << "Authkey already present!";
#endif
}
} else {
//
}
}
return true;
}
bool Configuration::checkMqtt(const std::string& mqtt) {
//MQTT topic must have 128 bit = 16 bytes = 32 hex chars
//but can have more with some extra '/', therefore remove all '/'
......
......@@ -53,7 +53,7 @@ public:
bool readGlobal();
/**
* Reads configuration (excpet global values) from global.conf (located at _cfgFilePath).
* Reads configuration (except global values) from global.conf (located at _cfgFilePath).
* Detects which sensor types are required and dynamically opens required libraries.
* Invokes dynamic libraries to read their configuration.
*
......@@ -61,6 +61,14 @@ public:
*/
bool read();
/**
* Reads the authentication keys and forwards them to the HttpsServer
*
* @param server The Rest API server where to add the authkeys
* @return true on success, false otherwise
*/
bool readAuthkeys(HttpsServer& server);
/**
* Read and set general sensor values (like interval, minvalues, ...).
* @param sensor The sensor to be configured
......
......@@ -74,7 +74,7 @@ void HttpsServer::requestHandler::operator()(server::request const &request, ser
if (auth_key == "authkey" && (action == "avg")) {
//check if authkey is valid
if (check_authkey(auth_value)) {
if (_httpsServer.check_authkey(auth_value, permission::GETReq)) {
response = "Plugin not found!";
connection->set_status(server::connection::not_found);
......@@ -153,7 +153,7 @@ void HttpsServer::requestHandler::operator()(server::request const &request, ser
if (auth_key == "authkey" && ((action == "start") || (action == "stop"))) {
//check if authkey is valid
if (check_authkey(auth_value)) {
if (_httpsServer.check_authkey(auth_value, permission::PUTReq)) {
response = "Plugin not found!";
connection->set_status(server::connection::not_found);
......@@ -202,10 +202,6 @@ void HttpsServer::requestHandler::log(const server::string_type& message) {
LOG(error) << message;
}
bool HttpsServer::requestHandler::check_authkey(const std::string& authkey) {
return authkey == "qwertz" ? true : false;
}
HttpsServer::HttpsServer(restAPISettings_t restAPISettings, pluginVector_t& plugins) :
_plugins(plugins), _handler(*this) {
......@@ -226,6 +222,14 @@ HttpsServer::~HttpsServer() {
delete _server;
}
bool HttpsServer::check_authkey(const std::string& authkey, permission requiredPerm) {
authkeyMap_t::iterator it = _authkeys.find(authkey);
if (it != _authkeys.end()) {
return it->second[requiredPerm];
}
return false;
}
/*
std::string HttpsServer::password_callback(std::size_t max_length, asio::ssl::context_base::password_purpose purpose) {
return std::string("pwd");
......
......@@ -8,6 +8,12 @@
#ifndef HTTPSSERVER_H_
#define HTTPSSERVER_H_
#define NUM_PERMISSIONS 8
#include <utility>
#include <map>
#include <bitset>
//Caution: include order matters! server.hpp needs to be included first
#include <boost/network/protocol/http/server.hpp>
......@@ -25,6 +31,13 @@ typedef struct {
std::string dhFile;
} restAPISettings_t;
enum permission {
GETReq = 0,
PUTReq = 1
};
typedef std::map<std::string, std::bitset<NUM_PERMISSIONS>> authkeyMap_t;
/*
* Provides REST API services over configurable host and port.
*/
......@@ -34,6 +47,10 @@ public:
HttpsServer(restAPISettings_t restAPISettings, pluginVector_t& plugins);
virtual ~HttpsServer();
bool addAuthkey(authkeyMap_t::value_type authkey) {
return _authkeys.insert(authkey).second;
}
void run() {
_server->run();
}
......@@ -57,14 +74,6 @@ private:
void log(const server::string_type& message);
/*
* Check if the authkey is valid and/or authorized to make requests
*
* @param authkey The authkey to check
* @return True if authkey is valid/authorized, false otherwise
*/
bool check_authkey(const std::string& authkey);
private:
HttpsServer& _httpsServer; //to remember who is our parent. We need access to its _plugins
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
......@@ -74,7 +83,17 @@ private:
static std::string password_callback(std::size_t max_length, asio::ssl::context_base::password_purpose purpose);
*/
/*
* Check if the authkey is valid and has the permission requiredPerm associated
*
* @param authkey The authkey to check
* @param requiredPerm The permission which is required to pass the check
* @return True if authkey is valid/authorized, false otherwise
*/
bool check_authkey(const std::string& authkey, permission requiredPerm);
pluginVector_t& _plugins;
authkeyMap_t _authkeys;
server* _server;
requestHandler _handler;
......
......@@ -338,6 +338,7 @@ int main(int argc, char** argv) {
//MQTTPusher and Https server get their own threads
MQTTPusher mqttPusher(globalSettings.brokerPort, globalSettings.brokerHost, globalSettings.pluginSettings.mqttPrefix, plugins);
HttpsServer httpsServer(globalSettings.restAPISettings, plugins);
cfg.readAuthkeys(httpsServer);
boost::thread mqttThread(bind(&MQTTPusher::push, &mqttPusher));
boost::thread restThread(bind(&HttpsServer::run, &httpsServer));
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment