Compare commits
No commits in common. "b7cd1ce78e0f36cb832fa040b422d9435080c5e2" and "b66f1d4e0da9cb38e01820c09e67c2506d0f1a8a" have entirely different histories.
b7cd1ce78e
...
b66f1d4e0d
|
|
@ -1,47 +0,0 @@
|
|||
pipeline {
|
||||
agent any
|
||||
|
||||
options
|
||||
{
|
||||
skipDefaultCheckout(true)
|
||||
}
|
||||
stages
|
||||
{
|
||||
stage('Checkout')
|
||||
{
|
||||
steps
|
||||
{
|
||||
cleanWs()
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
stage('Run')
|
||||
{
|
||||
steps
|
||||
{
|
||||
sh 'ansible-playbook -vvvv --skip-tags cleanup,deploy -i ./playbooks/inventory.yaml ./playbooks/build.yaml'
|
||||
}
|
||||
}
|
||||
stage('Deploy')
|
||||
{
|
||||
when
|
||||
{
|
||||
expression
|
||||
{
|
||||
currentBuild.result == null || currentBuild.result == 'SUCCESS'
|
||||
}
|
||||
}
|
||||
steps
|
||||
{
|
||||
sh 'ansible-playbook --tags deploy -i ./playbooks/inventory.yaml ./playbooks/build.yaml'
|
||||
}
|
||||
}
|
||||
}
|
||||
post
|
||||
{
|
||||
always
|
||||
{
|
||||
sh 'ansible-playbook --tags cleanup -i ./playbooks/inventory.yaml ./playbooks/build.yaml'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
j7s-mosquitto-plugin (0.0.7-1) stable; urgency=medium
|
||||
j7s-mosquitto-plugin (0.0.1-1) unstable; urgency=medium
|
||||
|
||||
* New release.
|
||||
* Initial release.
|
||||
|
||||
-- James Pace <jpace121@gmail.com> Tues, 09 August 2022 01:53:50 +0000
|
||||
-- James Pace <jpace121@gmail.com> Sat, 26 Mar 2022 23:49:28 +0000
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ Section: misc
|
|||
Priority: optional
|
||||
|
||||
Package: j7s-mosquitto-plugin
|
||||
Architecture: amd64
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Authentication plugin for mosquitto for the j7s project.
|
||||
Authentication plugin for mosquitto for the j7s project.
|
||||
|
|
|
|||
|
|
@ -1,3 +1 @@
|
|||
default:
|
||||
- /home/jimmy/Develop/mosquitto-plugin/examples/key.pem
|
||||
- /home/jimmy/Develop/mosquitto-plugin/examples/service-key.pem
|
||||
default: /home/jimmy/Develop/mosquitto-plugin/examples/key.pem
|
||||
|
|
@ -1,14 +1,17 @@
|
|||
per_listener_settings false
|
||||
allow_anonymous false
|
||||
per_listener_settings true
|
||||
log_type all
|
||||
|
||||
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 8082
|
||||
protocol websockets
|
||||
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -31,10 +31,9 @@ token = r.json()['access_token']
|
|||
print(token)
|
||||
|
||||
client = paho.mqtt.client.Client(protocol=paho.mqtt.client.MQTTv5,
|
||||
transport="websockets")
|
||||
transport="tcp")
|
||||
client.username_pw_set("jimmy", password=token)
|
||||
client.tls_set()
|
||||
client.connect("mqtt.jpace121.net", port=443)
|
||||
client.connect("localhost", port=8081)
|
||||
|
||||
print("Waiting on connection.")
|
||||
time.sleep(20)
|
||||
|
|
|
|||
|
|
@ -4,26 +4,33 @@ 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.
|
||||
well_known = s.get("https://auth.jpace121.net/realms/jpace121-services/.well-known/openid-configuration", ).json()
|
||||
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.")
|
||||
token_url = well_known['token_endpoint']
|
||||
data = {"grant_type" : "password", "client_id" : "mqtt", "username" : "j7s-1"}
|
||||
# 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"}
|
||||
|
||||
# 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("j7s-1", password=token)
|
||||
client.tls_set(certfile="/home/jimmy/Develop/keycloak/jimmy-client.pem",
|
||||
keyfile="/home/jimmy/Develop/keycloak/jimmy-client-key.pem")
|
||||
client.connect("mqtt.jpace121.net", port=8883)
|
||||
client.username_pw_set("jimmy", password=token)
|
||||
client.connect("localhost", port=8081)
|
||||
|
||||
print("Waiting on connection.")
|
||||
time.sleep(5)
|
||||
time.sleep(20)
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9DBwMe+eHkYLfq076sFq75gepyaL4LQtX8qVlGjJCtLxV308L2d8XGC35VBxrIbx8Bs5sKT4e5s9suzO8FhGMQ==
|
||||
-----END PUBLIC KEY-----
|
||||
|
|
@ -27,5 +27,3 @@ std::string gen_token(
|
|||
const std::string &priv_key,
|
||||
const std::chrono::time_point<std::chrono::system_clock> &issue_time,
|
||||
const std::chrono::time_point<std::chrono::system_clock> &expr_time);
|
||||
|
||||
std::string toString(const char* c_str);
|
||||
|
|
|
|||
|
|
@ -1,124 +0,0 @@
|
|||
---
|
||||
- name: Setup container for building.
|
||||
hosts: localhost
|
||||
tasks:
|
||||
- name: Create a container
|
||||
containers.podman.podman_container:
|
||||
name: j7s-mosquitto-debian-builder
|
||||
image: docker.io/library/debian:bullseye
|
||||
volume: "{{ playbook_dir }}/..:/work/src:Z"
|
||||
command: 'sleep infinity'
|
||||
state: started
|
||||
- name: Add the container to inventory.
|
||||
ansible.builtin.add_host:
|
||||
name: j7s-mosquitto-debian-builder
|
||||
ansible_connection: containers.podman.podman
|
||||
ansible_user: root
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
changed_when: false
|
||||
- name: Set the container up for normal ansible stuff.
|
||||
delegate_to: j7s-mosquitto-debian-builder
|
||||
raw: bash -c "apt update && apt install -y python3"
|
||||
|
||||
- name: Setup build environment.
|
||||
hosts: j7s-mosquitto-debian-builder
|
||||
become: true
|
||||
tasks:
|
||||
- name: Update cache
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
- name: Install build dependencies.
|
||||
ansible.builtin.apt:
|
||||
package:
|
||||
- build-essential
|
||||
- cmake
|
||||
- dh-cmake
|
||||
- mosquitto-dev
|
||||
- libmosquitto-dev
|
||||
- libssl-dev
|
||||
- libyaml-cpp-dev
|
||||
- fakeroot
|
||||
- devscripts
|
||||
- debhelper
|
||||
state: latest
|
||||
|
||||
- name: Build package.
|
||||
hosts: j7s-mosquitto-debian-builder
|
||||
tasks:
|
||||
- name: Call debuild.
|
||||
ansible.builtin.shell:
|
||||
chdir: "/work/src"
|
||||
cmd: ls && debuild -us -uc -b
|
||||
- name: Copy deb file back to the main directory.
|
||||
ansible.builtin.shell:
|
||||
cmd: "cp -r /work/*.deb /work/src/."
|
||||
- name: Copy changes file back to the main directory.
|
||||
ansible.builtin.shell:
|
||||
cmd: "cp -r /work/*.changes /work/src/."
|
||||
- name: Copy buildinfo file back to the main directory.
|
||||
ansible.builtin.shell:
|
||||
cmd: "cp -r /work/*.buildinfo /work/src/."
|
||||
|
||||
- name: Upload to packaging server.
|
||||
hosts: packaging
|
||||
tags: deploy
|
||||
tasks:
|
||||
- name: Copy package to packaging server.
|
||||
ansible.builtin.copy:
|
||||
src: "{{ item }}"
|
||||
dest: ~/public/apt/mini-dinstall/incoming/
|
||||
with_fileglob: ../j7s-*.deb
|
||||
register: copied_files
|
||||
- name: Fail if we didn't copy exactly two files. (debug and normal)
|
||||
ansible.builtin.fail:
|
||||
msg: "Didn't find exactly two deb file."
|
||||
when: copied_files.results | length != 2
|
||||
- name: Ditto the changes file.
|
||||
ansible.builtin.copy:
|
||||
src: "{{ item }}"
|
||||
dest: ~/public/apt/mini-dinstall/incoming/
|
||||
with_fileglob: ../j7s-*.changes
|
||||
register: copied_changes
|
||||
- name: Fail if we didn't copy exactly one file.
|
||||
ansible.builtin.fail:
|
||||
msg: "Didn't find exactly one changes file."
|
||||
when: copied_changes.results | length != 1
|
||||
- name: Ditto the buildinfo file.
|
||||
ansible.builtin.copy:
|
||||
src: "{{ item }}"
|
||||
dest: ~/public/apt/mini-dinstall/incoming/
|
||||
with_fileglob: ../j7s-*.buildinfo
|
||||
register: copied_buildinfo
|
||||
- name: Fail if we didn't copy exactly one file.
|
||||
ansible.builtin.fail:
|
||||
msg: "Didn't find exactly one buildinfo file."
|
||||
when: copied_buildinfo.results | length != 1
|
||||
- name: Run mini-dinstall.
|
||||
ansible.builtin.shell:
|
||||
cmd: "mini-dinstall --batch"
|
||||
- name: wait dinstall to do its thing
|
||||
ansible.builtin.pause:
|
||||
seconds: 3
|
||||
|
||||
- name: Build and push image.
|
||||
hosts: localhost
|
||||
tags: deploy
|
||||
tasks:
|
||||
- name: Build and push image.
|
||||
containers.podman.podman_image:
|
||||
name: j7s-mosquitto
|
||||
tag: latest
|
||||
force: true
|
||||
path: ..
|
||||
push: yes
|
||||
push_args:
|
||||
dest: registry.jpace121.net
|
||||
|
||||
- name: Cleanup
|
||||
hosts: localhost
|
||||
tags: cleanup
|
||||
tasks:
|
||||
- name: Stop the container.
|
||||
containers.podman.podman_container:
|
||||
name: j7s-mosquitto-debian-builder
|
||||
state: absent
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
all:
|
||||
hosts:
|
||||
packaging:
|
||||
ansible_host: packages.jpace121.net
|
||||
ansible_user: packaging
|
||||
|
|
@ -18,11 +18,10 @@
|
|||
#include <j7s-plugin/AuthList.hpp>
|
||||
#include <j7s-plugin/Authorizer.hpp>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
// Util.
|
||||
std::tuple<bool, bool> checkACL(const std::string &user, const YAML::Node &aclFile);
|
||||
std::vector<std::string> getKey(const std::string &user, const YAML::Node &keyFile);
|
||||
std::optional<std::string> getKey(const std::string &user, const YAML::Node &keyFile);
|
||||
|
||||
// Class implementation.
|
||||
Authorizer::Authorizer(const std::string &keyFilePath, const std::string &aclFilePath) :
|
||||
|
|
@ -38,20 +37,15 @@ bool Authorizer::add(const std::string &token, const std::string &username)
|
|||
return false;
|
||||
}
|
||||
|
||||
const auto keys = getKey(username, _keyFile);
|
||||
const auto key = getKey(username, _keyFile);
|
||||
|
||||
// Do any of the keys validate the token?
|
||||
const bool validated = [token, username, keys]() {
|
||||
for (const auto key : keys)
|
||||
if (not key)
|
||||
{
|
||||
if (validate(token, username, key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
std::cerr << "Could not read key for user." << std::endl;
|
||||
return false;
|
||||
}();
|
||||
}
|
||||
|
||||
const bool validated = validate(token, username, key.value());
|
||||
if (not validated)
|
||||
{
|
||||
std::cerr << "Not validated." << std::endl;
|
||||
|
|
@ -129,45 +123,18 @@ std::tuple<bool, bool> checkACL(const std::string &user, const YAML::Node &aclFi
|
|||
return std::make_tuple(can_read, can_write);
|
||||
}
|
||||
|
||||
std::vector<std::string> getKey(const std::string &user, const YAML::Node &keyFile)
|
||||
{
|
||||
|
||||
// Find this user's entry or the default one.
|
||||
YAML::Node userKey;
|
||||
if(keyFile[user])
|
||||
{
|
||||
userKey = keyFile[user];
|
||||
}
|
||||
else
|
||||
std::optional<std::string> getKey(const std::string &user, const YAML::Node &keyFile)
|
||||
{
|
||||
// TODO: Make sure default exists.
|
||||
userKey = keyFile["default"];
|
||||
}
|
||||
|
||||
// Get the paths from the yaml file as std::filesystem::paths.
|
||||
std::vector<std::filesystem::path> paths;
|
||||
if(not userKey.IsSequence())
|
||||
std::filesystem::path pathToKey;
|
||||
if (keyFile[user])
|
||||
{
|
||||
paths.emplace_back(userKey.as<std::string>());
|
||||
pathToKey = std::filesystem::path(keyFile[user].as<std::string>());
|
||||
}
|
||||
else
|
||||
{
|
||||
for(const auto key : userKey)
|
||||
{
|
||||
paths.emplace_back(key.as<std::string>());
|
||||
}
|
||||
pathToKey = std::filesystem::path(keyFile["default"].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;
|
||||
return read_key(std::filesystem::absolute(pathToKey).string());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,10 +53,10 @@ int mosquitto_plugin_init(
|
|||
std::filesystem::path aclFilePath;
|
||||
for (int index = 0; index < option_count; index++)
|
||||
{
|
||||
const auto key = toString(options[index].key);
|
||||
const auto key = std::string(options[index].key);
|
||||
if (key == "key_file")
|
||||
{
|
||||
std::string key_file_string = toString(options[index].value);
|
||||
std::string key_file_string = std::string(options[index].value);
|
||||
if (key_file_string.empty())
|
||||
{
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "key_file not set.");
|
||||
|
|
@ -66,7 +66,7 @@ int mosquitto_plugin_init(
|
|||
}
|
||||
else if (key == "acl_file")
|
||||
{
|
||||
std::string acl_file_string = toString(options[index].value);
|
||||
std::string acl_file_string = std::string(options[index].value);
|
||||
if (acl_file_string.empty())
|
||||
{
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "acl_file not set.");
|
||||
|
|
@ -124,11 +124,11 @@ int j7s_auth_basic_auth_callback(int event, void *event_data, void *userdata)
|
|||
|
||||
if (!auth_data->password)
|
||||
{
|
||||
authorizer->add_unknown(toString(auth_data->username));
|
||||
authorizer->add_unknown(std::string(auth_data->username));
|
||||
return MOSQ_ERR_PLUGIN_DEFER;
|
||||
}
|
||||
bool is_authed =
|
||||
authorizer->add(toString(auth_data->password), toString(auth_data->username));
|
||||
authorizer->add(std::string(auth_data->password), std::string(auth_data->username));
|
||||
|
||||
if (is_authed)
|
||||
{
|
||||
|
|
@ -150,26 +150,24 @@ int j7s_acl_check_callback(int event, void *event_data, void *userdata)
|
|||
struct mosquitto_evt_acl_check *acl_data =
|
||||
static_cast<struct mosquitto_evt_acl_check *>(event_data);
|
||||
|
||||
const std::string username = toString(mosquitto_client_username(acl_data->client));
|
||||
const std::string username = std::string(mosquitto_client_username(acl_data->client));
|
||||
|
||||
if (authorizer->is_unknown(username))
|
||||
{
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "ACL callback without username");
|
||||
return MOSQ_ERR_PLUGIN_DEFER;
|
||||
}
|
||||
|
||||
switch (acl_data->access)
|
||||
{
|
||||
case MOSQ_ACL_SUBSCRIBE:
|
||||
return (authorizer->can_read(username) ? MOSQ_ERR_SUCCESS : MOSQ_ERR_ACL_DENIED);
|
||||
return MOSQ_ERR_PLUGIN_DEFER;
|
||||
case MOSQ_ACL_UNSUBSCRIBE:
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
return MOSQ_ERR_PLUGIN_DEFER;
|
||||
case MOSQ_ACL_WRITE:
|
||||
return (authorizer->can_write(username) ? MOSQ_ERR_SUCCESS : MOSQ_ERR_ACL_DENIED);
|
||||
case MOSQ_ACL_READ:
|
||||
return (authorizer->can_read(username) ? MOSQ_ERR_SUCCESS : MOSQ_ERR_ACL_DENIED);
|
||||
default:
|
||||
mosquitto_log_printf(MOSQ_LOG_ERR, "Unhandled ACL check for user: %s", username.c_str());
|
||||
return MOSQ_ERR_ACL_DENIED;
|
||||
}
|
||||
}
|
||||
|
|
@ -179,7 +177,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 = toString(mosquitto_client_username(disconnect_data->client));
|
||||
const std::string username = std::string(mosquitto_client_username(disconnect_data->client));
|
||||
|
||||
authorizer->logout(username);
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ 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();
|
||||
|
|
@ -119,15 +120,3 @@ std::string gen_token(
|
|||
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string toString(const char* c_str)
|
||||
{
|
||||
if(c_str)
|
||||
{
|
||||
return std::string(c_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue