diff --git a/examples/keys.yaml b/examples/keys.yaml index 0120f98..e90ec42 100644 --- a/examples/keys.yaml +++ b/examples/keys.yaml @@ -1 +1,3 @@ -default: /home/jimmy/Develop/mosquitto-plugin/examples/key.pem \ No newline at end of file +default: + - /home/jimmy/Develop/mosquitto-plugin/examples/key.pem + - /home/jimmy/Develop/mosquitto-plugin/examples/service-key.pem \ No newline at end of file diff --git a/examples/mosquitto.conf b/examples/mosquitto.conf index c471e7b..263b2b7 100644 --- a/examples/mosquitto.conf +++ b/examples/mosquitto.conf @@ -1,17 +1,14 @@ -per_listener_settings true +per_listener_settings false +allow_anonymous false 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 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 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 diff --git a/examples/python-device-client.py b/examples/python-device-client.py index 128db6e..37cdcc9 100644 --- a/examples/python-device-client.py +++ b/examples/python-device-client.py @@ -31,9 +31,10 @@ token = r.json()['access_token'] print(token) client = paho.mqtt.client.Client(protocol=paho.mqtt.client.MQTTv5, - transport="tcp") + transport="websockets") 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.") time.sleep(20) diff --git a/examples/python-direct-client.py b/examples/python-direct-client.py index b394714..1cbaca5 100644 --- a/examples/python-direct-client.py +++ b/examples/python-direct-client.py @@ -4,33 +4,24 @@ import time import paho.mqtt.client 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.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") # Get urls. -print("Before get.") -well_known = s.get("https://nginx-test.internal.jpace121.net:8443/realms/jpace121-main/.well-known/openid-configuration", ).json() -print("After get.") +well_known = s.get("https://auth.jpace121.net/realms/jpace121-services/.well-known/openid-configuration", ).json() token_url = well_known['token_endpoint'] -# Override for now, url doesn't include port... -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"} +data = {"grant_type" : "password", "client_id" : "mqtt", "username" : "j7s-1"} # Request token. r = s.post(token_url, data=data) +print(r.json()) token = r.json()['access_token'] client = paho.mqtt.client.Client(protocol=paho.mqtt.client.MQTTv5, transport="tcp") -client.username_pw_set("jimmy", password=token) +client.username_pw_set("j7s-1", password=token) client.connect("localhost", port=8081) print("Waiting on connection.") -time.sleep(20) +time.sleep(5) diff --git a/examples/service-key.pem b/examples/service-key.pem new file mode 100644 index 0000000..92e0f64 --- /dev/null +++ b/examples/service-key.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9DBwMe+eHkYLfq076sFq75gepyaL4LQtX8qVlGjJCtLxV308L2d8XGC35VBxrIbx8Bs5sKT4e5s9suzO8FhGMQ== +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/src/Authorizer.cpp b/src/Authorizer.cpp index eb70092..b1b90e7 100644 --- a/src/Authorizer.cpp +++ b/src/Authorizer.cpp @@ -18,10 +18,11 @@ #include #include #include +#include // Util. std::tuple checkACL(const std::string &user, const YAML::Node &aclFile); -std::optional getKey(const std::string &user, const YAML::Node &keyFile); +std::vector getKey(const std::string &user, const YAML::Node &keyFile); // Class implementation. 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; } - const auto key = getKey(username, _keyFile); + const auto keys = getKey(username, _keyFile); - if (not key) - { - std::cerr << "Could not read key for user." << std::endl; + // Do any of the keys validate the token? + const bool validated = [token, username, keys]() { + for (const auto key : keys) + { + std::cout << "Trying..." << std::endl; + if (validate(token, username, key)) + { + return true; + } + } return false; - } + }(); - const bool validated = validate(token, username, key.value()); if (not validated) { std::cerr << "Not validated." << std::endl; @@ -123,18 +130,45 @@ std::tuple checkACL(const std::string &user, const YAML::Node &aclFi return std::make_tuple(can_read, can_write); } -std::optional getKey(const std::string &user, const YAML::Node &keyFile) +std::vector getKey(const std::string &user, const YAML::Node &keyFile) { - // TODO: Make sure default exists. - std::filesystem::path pathToKey; - if (keyFile[user]) + + // Find this user's entry or the default one. + YAML::Node userKey; + if(keyFile[user]) { - pathToKey = std::filesystem::path(keyFile[user].as()); + userKey = keyFile[user]; } else { - pathToKey = std::filesystem::path(keyFile["default"].as()); + // 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 paths; + if(not userKey.IsSequence()) + { + paths.emplace_back(userKey.as()); + } + else + { + for(const auto key : userKey) + { + paths.emplace_back(key.as()); + } + } + + // Now convert to an array of optional keys. + std::vector 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; } diff --git a/src/utils.cpp b/src/utils.cpp index 0f7aaf8..33430e6 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -56,7 +56,6 @@ bool validate(const std::string &token, const std::string &username, const std:: } catch (std::system_error &exception) { - std::cerr << "Token Verification Failed: " << exception.what() << std::endl; return false; } auto claims = decoded_token.get_payload_claims();