Only the load the plugin once. Support multiple keys per user.
This commit is contained in:
parent
1a68a5ce8a
commit
b62da77718
|
|
@ -1 +1,3 @@
|
||||||
default: /home/jimmy/Develop/mosquitto-plugin/examples/key.pem
|
default:
|
||||||
|
- /home/jimmy/Develop/mosquitto-plugin/examples/key.pem
|
||||||
|
- /home/jimmy/Develop/mosquitto-plugin/examples/service-key.pem
|
||||||
|
|
@ -1,17 +1,14 @@
|
||||||
per_listener_settings true
|
per_listener_settings false
|
||||||
|
allow_anonymous false
|
||||||
log_type all
|
log_type all
|
||||||
|
|
||||||
|
auth_plugin /home/jimmy/Develop/mosquitto-plugin/build/libj7s-plugin.so
|
||||||
|
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 8082
|
listener 8082
|
||||||
protocol websockets
|
protocol websockets
|
||||||
allow_anonymous false
|
|
||||||
auth_plugin /home/jimmy/Develop/mosquitto-plugin/build/libj7s-plugin.so
|
|
||||||
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
|
listener 8081
|
||||||
protocol mqtt
|
protocol mqtt
|
||||||
allow_anonymous false
|
|
||||||
auth_plugin /home/jimmy/Develop/mosquitto-plugin/build/libj7s-plugin.so
|
|
||||||
auth_opt_key_file /home/jimmy/Develop/mosquitto-plugin/examples/keys.yaml
|
|
||||||
auth_opt_acl_file /home/jimmy/Develop/mosquitto-plugin/examples/acl.yaml
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,10 @@ token = r.json()['access_token']
|
||||||
print(token)
|
print(token)
|
||||||
|
|
||||||
client = paho.mqtt.client.Client(protocol=paho.mqtt.client.MQTTv5,
|
client = paho.mqtt.client.Client(protocol=paho.mqtt.client.MQTTv5,
|
||||||
transport="tcp")
|
transport="websockets")
|
||||||
client.username_pw_set("jimmy", password=token)
|
client.username_pw_set("jimmy", password=token)
|
||||||
client.connect("localhost", port=8081)
|
client.tls_set()
|
||||||
|
client.connect("mqtt.jpace121.net", port=443)
|
||||||
|
|
||||||
print("Waiting on connection.")
|
print("Waiting on connection.")
|
||||||
time.sleep(20)
|
time.sleep(20)
|
||||||
|
|
|
||||||
|
|
@ -4,33 +4,24 @@ import time
|
||||||
import paho.mqtt.client
|
import paho.mqtt.client
|
||||||
import time
|
import time
|
||||||
|
|
||||||
# RESULT=`curl --cacert ./ca.pem --cert jimmy-client.pem --key jimmy-client-key.pem --data "grant_type=password&client_id=test&username=jimmy&password=1234" https://nginx-test.internal.jpace121.net:8443/realms/master/protocol/openid-connect/token`
|
|
||||||
|
|
||||||
s = requests.Session()
|
s = requests.Session()
|
||||||
s.verify = "/home/jimmy/Develop/mosquitto-plugin/test/ca.pem"
|
|
||||||
s.cert = ("/home/jimmy/Develop/keycloak/jimmy-client.pem", "/home/jimmy/Develop/keycloak/jimmy-client-key.pem")
|
s.cert = ("/home/jimmy/Develop/keycloak/jimmy-client.pem", "/home/jimmy/Develop/keycloak/jimmy-client-key.pem")
|
||||||
|
|
||||||
|
|
||||||
# Get urls.
|
# Get urls.
|
||||||
print("Before get.")
|
well_known = s.get("https://auth.jpace121.net/realms/jpace121-services/.well-known/openid-configuration", ).json()
|
||||||
well_known = s.get("https://nginx-test.internal.jpace121.net:8443/realms/jpace121-main/.well-known/openid-configuration", ).json()
|
|
||||||
print("After get.")
|
|
||||||
token_url = well_known['token_endpoint']
|
token_url = well_known['token_endpoint']
|
||||||
# Override for now, url doesn't include port...
|
data = {"grant_type" : "password", "client_id" : "mqtt", "username" : "j7s-1"}
|
||||||
token_url = "https://nginx-test.internal.jpace121.net:8443/realms/jpace121-main/protocol/openid-connect/token"
|
|
||||||
# RESULT=`curl --cacert ./ca.pem --cert jimmy-client.pem --key jimmy-client-key.pem --data "grant_type=password&client_id=mqtt&username=jimmy&password=1234" https://nginx-test.internal.jpace121.net:8443/realms/jpace121-main/protocol/openid-connect/token`
|
|
||||||
|
|
||||||
|
|
||||||
data = {"grant_type" : "password", "client_id" : "mqtt", "username" : "jimmy", "password": "1234"}
|
|
||||||
|
|
||||||
# Request token.
|
# Request token.
|
||||||
r = s.post(token_url, data=data)
|
r = s.post(token_url, data=data)
|
||||||
|
print(r.json())
|
||||||
token = r.json()['access_token']
|
token = r.json()['access_token']
|
||||||
|
|
||||||
client = paho.mqtt.client.Client(protocol=paho.mqtt.client.MQTTv5,
|
client = paho.mqtt.client.Client(protocol=paho.mqtt.client.MQTTv5,
|
||||||
transport="tcp")
|
transport="tcp")
|
||||||
client.username_pw_set("jimmy", password=token)
|
client.username_pw_set("j7s-1", password=token)
|
||||||
client.connect("localhost", port=8081)
|
client.connect("localhost", port=8081)
|
||||||
|
|
||||||
print("Waiting on connection.")
|
print("Waiting on connection.")
|
||||||
time.sleep(20)
|
time.sleep(5)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9DBwMe+eHkYLfq076sFq75gepyaL4LQtX8qVlGjJCtLxV308L2d8XGC35VBxrIbx8Bs5sKT4e5s9suzO8FhGMQ==
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
|
|
@ -18,10 +18,11 @@
|
||||||
#include <j7s-plugin/AuthList.hpp>
|
#include <j7s-plugin/AuthList.hpp>
|
||||||
#include <j7s-plugin/Authorizer.hpp>
|
#include <j7s-plugin/Authorizer.hpp>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
// Util.
|
// Util.
|
||||||
std::tuple<bool, bool> checkACL(const std::string &user, const YAML::Node &aclFile);
|
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);
|
std::vector<std::string> getKey(const std::string &user, const YAML::Node &keyFile);
|
||||||
|
|
||||||
// Class implementation.
|
// Class implementation.
|
||||||
Authorizer::Authorizer(const std::string &keyFilePath, const std::string &aclFilePath) :
|
Authorizer::Authorizer(const std::string &keyFilePath, const std::string &aclFilePath) :
|
||||||
|
|
@ -37,15 +38,21 @@ bool Authorizer::add(const std::string &token, const std::string &username)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto key = getKey(username, _keyFile);
|
const auto keys = getKey(username, _keyFile);
|
||||||
|
|
||||||
if (not key)
|
// Do any of the keys validate the token?
|
||||||
|
const bool validated = [token, username, keys]() {
|
||||||
|
for (const auto key : keys)
|
||||||
{
|
{
|
||||||
std::cerr << "Could not read key for user." << std::endl;
|
std::cout << "Trying..." << std::endl;
|
||||||
return false;
|
if (validate(token, username, key))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}();
|
||||||
|
|
||||||
const bool validated = validate(token, username, key.value());
|
|
||||||
if (not validated)
|
if (not validated)
|
||||||
{
|
{
|
||||||
std::cerr << "Not validated." << std::endl;
|
std::cerr << "Not validated." << std::endl;
|
||||||
|
|
@ -123,18 +130,45 @@ std::tuple<bool, bool> checkACL(const std::string &user, const YAML::Node &aclFi
|
||||||
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)
|
std::vector<std::string> getKey(const std::string &user, const YAML::Node &keyFile)
|
||||||
{
|
{
|
||||||
// TODO: Make sure default exists.
|
|
||||||
std::filesystem::path pathToKey;
|
// Find this user's entry or the default one.
|
||||||
if (keyFile[user])
|
YAML::Node userKey;
|
||||||
|
if(keyFile[user])
|
||||||
{
|
{
|
||||||
pathToKey = std::filesystem::path(keyFile[user].as<std::string>());
|
userKey = keyFile[user];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pathToKey = std::filesystem::path(keyFile["default"].as<std::string>());
|
// TODO: Make sure default exists.
|
||||||
|
userKey = keyFile["default"];
|
||||||
}
|
}
|
||||||
|
|
||||||
return read_key(std::filesystem::absolute(pathToKey).string());
|
// Get the paths from the yaml file as std::filesystem::paths.
|
||||||
|
std::vector<std::filesystem::path> paths;
|
||||||
|
if(not userKey.IsSequence())
|
||||||
|
{
|
||||||
|
paths.emplace_back(userKey.as<std::string>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(const auto key : userKey)
|
||||||
|
{
|
||||||
|
paths.emplace_back(key.as<std::string>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now convert to an array of optional keys.
|
||||||
|
std::vector<std::string> keys;
|
||||||
|
for(const auto path : paths)
|
||||||
|
{
|
||||||
|
const auto key = read_key(std::filesystem::absolute(path).string());
|
||||||
|
if(key)
|
||||||
|
{
|
||||||
|
keys.emplace_back(key.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ bool validate(const std::string &token, const std::string &username, const std::
|
||||||
}
|
}
|
||||||
catch (std::system_error &exception)
|
catch (std::system_error &exception)
|
||||||
{
|
{
|
||||||
std::cerr << "Token Verification Failed: " << exception.what() << std::endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto claims = decoded_token.get_payload_claims();
|
auto claims = decoded_token.get_payload_claims();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue