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
|
||||
allow_anonymous false
|
||||
auth_plugin /home/jimmy/Develop/mosquitto-plugin/build/libj7s-plugin.so
|
||||
auth_opt_issuer https://auth.jpace121.net/realms/jpace121-main
|
||||
auth_opt_public_key /home/jimmy/Develop/mosquitto-plugin/examples/key.pem
|
||||
auth_opt_key_file /home/jimmy/Develop/mosquitto-plugin/examples/keys.yaml
|
||||
auth_opt_acl_file /home/jimmy/Develop/mosquitto-plugin/examples/acl.yaml
|
||||
|
||||
listener 8081
|
||||
protocol mqtt
|
||||
allow_anonymous false
|
||||
auth_plugin /home/jimmy/Develop/mosquitto-plugin/build/libj7s-plugin.so
|
||||
auth_opt_issuer https://auth.jpace121.net/realms/jpace121-main
|
||||
auth_opt_public_key /home/jimmy/Develop/mosquitto-plugin/examples/key.pem
|
||||
auth_opt_key_file /home/jimmy/Develop/mosquitto-plugin/examples/keys.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");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
class Authorizer
|
||||
{
|
||||
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);
|
||||
void add_unknown(const std::string& username);
|
||||
bool is_unknown(const std::string& username);
|
||||
|
|
@ -38,6 +38,7 @@ private:
|
|||
AuthList _unknownList;
|
||||
|
||||
YAML::Node _aclFile;
|
||||
YAML::Node _keyFile;
|
||||
|
||||
std::string _pub_key;
|
||||
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(
|
||||
const std::string & token,
|
||||
const std::string & username,
|
||||
const std::string & issuer,
|
||||
const std::string & pub_key);
|
||||
|
||||
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");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -18,30 +18,31 @@
|
|||
#include <j7s-plugin/Authorizer.hpp>
|
||||
|
||||
#include <tuple>
|
||||
#include <filesystem>
|
||||
|
||||
// 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.
|
||||
Authorizer::Authorizer(
|
||||
const std::string & pub_key, const std::string & issuer, const std::string & aclFilePath) :
|
||||
_pub_key{pub_key}, _issuer{issuer}, _aclFile{aclFilePath}
|
||||
const std::string & keyFilePath, const std::string & 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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.
|
||||
// TODO: Make sure default is in ACL file.
|
||||
if (not _aclFile[username])
|
||||
{
|
||||
const auto checkACL(_aclFile["default"]);
|
||||
return true;
|
||||
}
|
||||
const auto [can_read, can_write] = checkACL(_aclFile[username]);
|
||||
const auto [can_read, can_write] = checkACL(username, _aclFile);
|
||||
|
||||
if (can_read)
|
||||
{
|
||||
|
|
@ -87,19 +82,57 @@ void Authorizer::logout(const std::string & username)
|
|||
_unknownList.remove(username);
|
||||
}
|
||||
|
||||
// Util.
|
||||
std::tuple<bool, bool> checkACL(const YAML::Node& user)
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
// 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_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;
|
||||
}
|
||||
if(user["can_write"] and user["can_write"].as<bool>())
|
||||
if(userDict["can_write"] and userDict["can_write"].as<bool>())
|
||||
{
|
||||
can_write = true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (option_count < 3)
|
||||
if (option_count < 2)
|
||||
{
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Missing an option. Found: %d", option_count);
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
|
||||
std::string public_key;
|
||||
std::string issuer;
|
||||
std::filesystem::path keyFilePath;
|
||||
std::filesystem::path aclFilePath;
|
||||
for (int index = 0; index < option_count; index++)
|
||||
{
|
||||
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));
|
||||
if (not key or key->empty())
|
||||
std::string key_file_string = std::string(options[index].value);
|
||||
if (key_file_string.empty())
|
||||
{
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Could not read public key.");
|
||||
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.");
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "key_file not set.");
|
||||
return MOSQ_ERR_INVAL;
|
||||
}
|
||||
keyFilePath = std::filesystem::path(key_file_string);
|
||||
}
|
||||
else if (key == "acl_file")
|
||||
{
|
||||
|
|
@ -89,7 +79,8 @@ int mosquitto_plugin_init(
|
|||
}
|
||||
|
||||
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.
|
||||
mosquitto_callback_register(
|
||||
|
|
@ -187,6 +178,7 @@ int j7s_disconnect_callback(int event, void * event_data, void * userdata)
|
|||
{
|
||||
struct mosquitto_evt_disconnect * disconnect_data =
|
||||
static_cast<struct mosquitto_evt_disconnect *>(event_data);
|
||||
|
||||
const std::string username = std::string(mosquitto_client_username(disconnect_data->client));
|
||||
|
||||
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(
|
||||
const std::string & token,
|
||||
const std::string & username,
|
||||
const std::string & issuer,
|
||||
const std::string & pub_key)
|
||||
{
|
||||
const auto decoded_token = jwt::decode(token);
|
||||
|
||||
// Is the token valid?
|
||||
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
|
||||
{
|
||||
verifier.verify(decoded_token);
|
||||
|
|
|
|||
Loading…
Reference in New Issue