Add key_file.
This commit is contained in:
parent
4f60efa87a
commit
5ef2e0b929
|
|
@ -0,0 +1 @@
|
||||||
|
default: /home/jimmy/Develop/mosquitto-plugin/examples/key.pem
|
||||||
|
|
@ -5,15 +5,13 @@ listener 8082
|
||||||
protocol websockets
|
protocol websockets
|
||||||
allow_anonymous false
|
allow_anonymous false
|
||||||
auth_plugin /home/jimmy/Develop/mosquitto-plugin/build/libj7s-plugin.so
|
auth_plugin /home/jimmy/Develop/mosquitto-plugin/build/libj7s-plugin.so
|
||||||
auth_opt_issuer https://auth.jpace121.net/realms/jpace121-main
|
auth_opt_key_file /home/jimmy/Develop/mosquitto-plugin/examples/keys.yaml
|
||||||
auth_opt_public_key /home/jimmy/Develop/mosquitto-plugin/examples/key.pem
|
|
||||||
auth_opt_acl_file /home/jimmy/Develop/mosquitto-plugin/examples/acl.yaml
|
auth_opt_acl_file /home/jimmy/Develop/mosquitto-plugin/examples/acl.yaml
|
||||||
|
|
||||||
listener 8081
|
listener 8081
|
||||||
protocol mqtt
|
protocol mqtt
|
||||||
allow_anonymous false
|
allow_anonymous false
|
||||||
auth_plugin /home/jimmy/Develop/mosquitto-plugin/build/libj7s-plugin.so
|
auth_plugin /home/jimmy/Develop/mosquitto-plugin/build/libj7s-plugin.so
|
||||||
auth_opt_issuer https://auth.jpace121.net/realms/jpace121-main
|
auth_opt_key_file /home/jimmy/Develop/mosquitto-plugin/examples/keys.yaml
|
||||||
auth_opt_public_key /home/jimmy/Develop/mosquitto-plugin/examples/key.pem
|
|
||||||
auth_opt_acl_file /home/jimmy/Develop/mosquitto-plugin/examples/acl.yaml
|
auth_opt_acl_file /home/jimmy/Develop/mosquitto-plugin/examples/acl.yaml
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2021 James Pace
|
// Copyright 2021-2022 James Pace
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
class Authorizer
|
class Authorizer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Authorizer(const std::string& pub_key, const std::string& issuer, const std::string& aclFilePath);
|
Authorizer(const std::string& keyFilePath, const std::string& aclFilePath);
|
||||||
static std::optional<std::string> read_key(const std::string& key_file);
|
static std::optional<std::string> read_key(const std::string& key_file);
|
||||||
void add_unknown(const std::string& username);
|
void add_unknown(const std::string& username);
|
||||||
bool is_unknown(const std::string& username);
|
bool is_unknown(const std::string& username);
|
||||||
|
|
@ -38,6 +38,7 @@ private:
|
||||||
AuthList _unknownList;
|
AuthList _unknownList;
|
||||||
|
|
||||||
YAML::Node _aclFile;
|
YAML::Node _aclFile;
|
||||||
|
YAML::Node _keyFile;
|
||||||
|
|
||||||
std::string _pub_key;
|
std::string _pub_key;
|
||||||
std::string _issuer;
|
std::string _issuer;
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ std::optional<std::string> read_key(const std::string & key_file);
|
||||||
std::tuple<bool, std::chrono::time_point<std::chrono::system_clock>> validate(
|
std::tuple<bool, std::chrono::time_point<std::chrono::system_clock>> validate(
|
||||||
const std::string & token,
|
const std::string & token,
|
||||||
const std::string & username,
|
const std::string & username,
|
||||||
const std::string & issuer,
|
|
||||||
const std::string & pub_key);
|
const std::string & pub_key);
|
||||||
|
|
||||||
std::string gen_token(
|
std::string gen_token(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2021 James Pace
|
// Copyright 2021-2022 James Pace
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
|
@ -18,30 +18,31 @@
|
||||||
#include <j7s-plugin/Authorizer.hpp>
|
#include <j7s-plugin/Authorizer.hpp>
|
||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
// Util.
|
// Util.
|
||||||
std::tuple<bool, bool> checkACL(const YAML::Node& user);
|
std::tuple<bool, bool> checkACL(const std::string& user, const YAML::Node& aclFile);
|
||||||
|
std::optional<std::string> getKey(const std::string& user, const YAML::Node& keyFile);
|
||||||
|
|
||||||
// Class implementation.
|
// Class implementation.
|
||||||
Authorizer::Authorizer(
|
Authorizer::Authorizer(
|
||||||
const std::string & pub_key, const std::string & issuer, const std::string & aclFilePath) :
|
const std::string & keyFilePath, const std::string & aclFilePath) :
|
||||||
_pub_key{pub_key}, _issuer{issuer}, _aclFile{aclFilePath}
|
_keyFile{keyFilePath}, _aclFile{aclFilePath}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Authorizer::add_unknown(const std::string & username)
|
|
||||||
{
|
|
||||||
_unknownList.add(username, time_T::max());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Authorizer::is_unknown(const std::string & username)
|
|
||||||
{
|
|
||||||
return (username.empty() or _unknownList.confirm(username));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Authorizer::add(const std::string & token, const std::string & username)
|
bool Authorizer::add(const std::string & token, const std::string & username)
|
||||||
{
|
{
|
||||||
const auto [validated, expr_time] = validate(token, username, _issuer, _pub_key);
|
const auto key = getKey(username, _keyFile);
|
||||||
|
|
||||||
|
if(not key)
|
||||||
|
{
|
||||||
|
std::cerr << "Could not read key for user." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto [validated, expr_time] = validate(token, username, key.value());
|
||||||
if (not validated)
|
if (not validated)
|
||||||
{
|
{
|
||||||
std::cerr << "Not validated." << std::endl;
|
std::cerr << "Not validated." << std::endl;
|
||||||
|
|
@ -49,13 +50,7 @@ bool Authorizer::add(const std::string & token, const std::string & username)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the ACL file.
|
// Check the ACL file.
|
||||||
// TODO: Make sure default is in ACL file.
|
const auto [can_read, can_write] = checkACL(username, _aclFile);
|
||||||
if (not _aclFile[username])
|
|
||||||
{
|
|
||||||
const auto checkACL(_aclFile["default"]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const auto [can_read, can_write] = checkACL(_aclFile[username]);
|
|
||||||
|
|
||||||
if (can_read)
|
if (can_read)
|
||||||
{
|
{
|
||||||
|
|
@ -87,19 +82,57 @@ void Authorizer::logout(const std::string & username)
|
||||||
_unknownList.remove(username);
|
_unknownList.remove(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Util.
|
void Authorizer::add_unknown(const std::string & username)
|
||||||
std::tuple<bool, bool> checkACL(const YAML::Node& user)
|
|
||||||
{
|
{
|
||||||
|
_unknownList.add(username, time_T::max());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Authorizer::is_unknown(const std::string & username)
|
||||||
|
{
|
||||||
|
return (username.empty() or _unknownList.confirm(username));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Util.
|
||||||
|
std::tuple<bool, bool> checkACL(const std::string& user, const YAML::Node& aclFile)
|
||||||
|
{
|
||||||
|
// TODO: Make sure default exists.
|
||||||
|
YAML::Node userDict;
|
||||||
|
if(aclFile[user])
|
||||||
|
{
|
||||||
|
userDict = aclFile[user];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
userDict = aclFile["default"];
|
||||||
|
}
|
||||||
|
|
||||||
bool can_read = false;
|
bool can_read = false;
|
||||||
bool can_write = false;
|
bool can_write = false;
|
||||||
if(user["can_read"] and user["can_read"].as<bool>())
|
if(userDict["can_read"] and userDict["can_read"].as<bool>())
|
||||||
{
|
{
|
||||||
can_read = true;
|
can_read = true;
|
||||||
}
|
}
|
||||||
if(user["can_write"] and user["can_write"].as<bool>())
|
if(userDict["can_write"] and userDict["can_write"].as<bool>())
|
||||||
{
|
{
|
||||||
can_write = true;
|
can_write = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_tuple(can_read, can_write);
|
return std::make_tuple(can_read, can_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> getKey(const std::string& user, const YAML::Node& keyFile)
|
||||||
|
{
|
||||||
|
// TODO: Make sure default exists.
|
||||||
|
std::filesystem::path pathToKey;
|
||||||
|
if(keyFile[user])
|
||||||
|
{
|
||||||
|
pathToKey = std::filesystem::path(keyFile[user].as<std::string>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pathToKey = std::filesystem::path(keyFile["default"].as<std::string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
return read_key(std::filesystem::absolute(pathToKey).string());
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,36 +45,26 @@ int mosquitto_plugin_init(
|
||||||
{
|
{
|
||||||
plugin_id = identifier;
|
plugin_id = identifier;
|
||||||
|
|
||||||
if (option_count < 3)
|
if (option_count < 2)
|
||||||
{
|
{
|
||||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Missing an option. Found: %d", option_count);
|
mosquitto_log_printf(MOSQ_LOG_ERR, "Missing an option. Found: %d", option_count);
|
||||||
return MOSQ_ERR_INVAL;
|
return MOSQ_ERR_INVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string public_key;
|
std::filesystem::path keyFilePath;
|
||||||
std::string issuer;
|
|
||||||
std::filesystem::path aclFilePath;
|
std::filesystem::path aclFilePath;
|
||||||
for (int index = 0; index < option_count; index++)
|
for (int index = 0; index < option_count; index++)
|
||||||
{
|
{
|
||||||
const auto key = std::string(options[index].key);
|
const auto key = std::string(options[index].key);
|
||||||
if (key == "public_key")
|
if (key == "key_file")
|
||||||
{
|
{
|
||||||
const auto key = read_key(std::string(options[index].value));
|
std::string key_file_string = std::string(options[index].value);
|
||||||
if (not key or key->empty())
|
if (key_file_string.empty())
|
||||||
{
|
{
|
||||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Could not read public key.");
|
mosquitto_log_printf(MOSQ_LOG_ERR, "key_file not set.");
|
||||||
return MOSQ_ERR_INVAL;
|
|
||||||
}
|
|
||||||
public_key = *key;
|
|
||||||
}
|
|
||||||
else if (key == "issuer")
|
|
||||||
{
|
|
||||||
issuer = std::string(options[index].value);
|
|
||||||
if (issuer.empty())
|
|
||||||
{
|
|
||||||
mosquitto_log_printf(MOSQ_LOG_ERR, "issuer not set.");
|
|
||||||
return MOSQ_ERR_INVAL;
|
return MOSQ_ERR_INVAL;
|
||||||
}
|
}
|
||||||
|
keyFilePath = std::filesystem::path(key_file_string);
|
||||||
}
|
}
|
||||||
else if (key == "acl_file")
|
else if (key == "acl_file")
|
||||||
{
|
{
|
||||||
|
|
@ -89,7 +79,8 @@ int mosquitto_plugin_init(
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizer = std::make_unique<Authorizer>(
|
authorizer = std::make_unique<Authorizer>(
|
||||||
public_key, issuer, std::filesystem::absolute(aclFilePath).string());
|
std::filesystem::absolute(keyFilePath).string(),
|
||||||
|
std::filesystem::absolute(aclFilePath).string());
|
||||||
|
|
||||||
// Register the callbacks.
|
// Register the callbacks.
|
||||||
mosquitto_callback_register(
|
mosquitto_callback_register(
|
||||||
|
|
@ -187,6 +178,7 @@ int j7s_disconnect_callback(int event, void * event_data, void * userdata)
|
||||||
{
|
{
|
||||||
struct mosquitto_evt_disconnect * disconnect_data =
|
struct mosquitto_evt_disconnect * disconnect_data =
|
||||||
static_cast<struct mosquitto_evt_disconnect *>(event_data);
|
static_cast<struct mosquitto_evt_disconnect *>(event_data);
|
||||||
|
|
||||||
const std::string username = std::string(mosquitto_client_username(disconnect_data->client));
|
const std::string username = std::string(mosquitto_client_username(disconnect_data->client));
|
||||||
|
|
||||||
authorizer->logout(username);
|
authorizer->logout(username);
|
||||||
|
|
|
||||||
|
|
@ -35,14 +35,13 @@ std::optional<std::string> read_key(const std::string & key_file)
|
||||||
std::tuple<bool, std::chrono::time_point<std::chrono::system_clock>> validate(
|
std::tuple<bool, std::chrono::time_point<std::chrono::system_clock>> validate(
|
||||||
const std::string & token,
|
const std::string & token,
|
||||||
const std::string & username,
|
const std::string & username,
|
||||||
const std::string & issuer,
|
|
||||||
const std::string & pub_key)
|
const std::string & pub_key)
|
||||||
{
|
{
|
||||||
const auto decoded_token = jwt::decode(token);
|
const auto decoded_token = jwt::decode(token);
|
||||||
|
|
||||||
// Is the token valid?
|
// Is the token valid?
|
||||||
const auto verifier =
|
const auto verifier =
|
||||||
jwt::verify().with_issuer(issuer).allow_algorithm(jwt::algorithm::rs256(pub_key));
|
jwt::verify().allow_algorithm(jwt::algorithm::rs256(pub_key));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
verifier.verify(decoded_token);
|
verifier.verify(decoded_token);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue