diff --git a/apps/mosquitto_ctrl/broker.c b/apps/mosquitto_ctrl/broker.c index a8f9ed42..c80946f4 100644 --- a/apps/mosquitto_ctrl/broker.c +++ b/apps/mosquitto_ctrl/broker.c @@ -30,8 +30,8 @@ void broker__print_usage(void) printf("\nBroker Control module\n"); printf("=======================\n"); - printf("Get plugin information: getPluginInfo\n"); - printf("List listeners : listListeners\n"); + printf("List plugins : listPlugins\n"); + printf("List listeners : listListeners\n"); } /* ################################################################ @@ -177,7 +177,7 @@ static void broker__payload_callback(struct mosq_ctrl *ctrl, long payloadlen, co if(j_error){ fprintf(stderr, "%s: Error: %s\n", j_command->valuestring, j_error->valuestring); }else{ - if(!strcasecmp(j_command->valuestring, "getPluginInfo")){ + if(!strcasecmp(j_command->valuestring, "listPlugins")){ print_plugin_info(j_response); }else if(!strcasecmp(j_command->valuestring, "listListeners")){ print_listeners(j_response); @@ -188,12 +188,12 @@ static void broker__payload_callback(struct mosq_ctrl *ctrl, long payloadlen, co cJSON_Delete(tree); } -static int broker__get_plugin_info(int argc, char *argv[], cJSON *j_command) +static int broker__list_plugins(int argc, char *argv[], cJSON *j_command) { UNUSED(argc); UNUSED(argv); - if(cJSON_AddStringToObject(j_command, "command", "getPluginInfo") == NULL + if(cJSON_AddStringToObject(j_command, "command", "listPlugins") == NULL ){ return MOSQ_ERR_NOMEM; @@ -257,8 +257,8 @@ int broker__main(int argc, char *argv[], struct mosq_ctrl *ctrl) } cJSON_AddItemToArray(j_commands, j_command); - if(!strcasecmp(argv[0], "getPluginInfo")){ - rc = broker__get_plugin_info(argc-1, &argv[1], j_command); + if(!strcasecmp(argv[0], "listPlugins")){ + rc = broker__list_plugins(argc-1, &argv[1], j_command); }else if(!strcasecmp(argv[0], "listListeners")){ rc = broker__list_listeners(argc-1, &argv[1], j_command); diff --git a/src/broker_control.c b/src/broker_control.c index 193fa04a..86b6e258 100644 --- a/src/broker_control.c +++ b/src/broker_control.c @@ -118,7 +118,7 @@ static int add_plugin_info(cJSON *j_plugins, mosquitto_plugin_id_t *pid) } -static int broker__process_get_plugin_info(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data) +static int broker__process_list_plugins(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data) { cJSON *tree, *jtmp, *j_data, *j_plugins; const char *admin_clientid, *admin_username; @@ -128,16 +128,16 @@ static int broker__process_get_plugin_info(cJSON *j_responses, struct mosquitto tree = cJSON_CreateObject(); if(tree == NULL){ - broker__command_reply(j_responses, context, "getPluginInfo", "Internal error", correlation_data); + broker__command_reply(j_responses, context, "listPlugins", "Internal error", correlation_data); return MOSQ_ERR_NOMEM; } admin_clientid = mosquitto_client_id(context); admin_username = mosquitto_client_username(context); - mosquitto_log_printf(MOSQ_LOG_INFO, "Broker: %s/%s | getPluginInfo", + mosquitto_log_printf(MOSQ_LOG_INFO, "Broker: %s/%s | listPlugins", admin_clientid, admin_username); - if(cJSON_AddStringToObject(tree, "command", "getPluginInfo") == NULL + if(cJSON_AddStringToObject(tree, "command", "listPlugins") == NULL || ((j_data = cJSON_AddObjectToObject(tree, "data")) == NULL) ){ @@ -168,7 +168,7 @@ static int broker__process_get_plugin_info(cJSON *j_responses, struct mosquitto internal_error: cJSON_Delete(tree); - broker__command_reply(j_responses, context, "getPluginInfo", "Internal error", correlation_data); + broker__command_reply(j_responses, context, "listPlugins", "Internal error", correlation_data); return MOSQ_ERR_NOMEM; } @@ -366,8 +366,8 @@ static int broker__handle_control(cJSON *j_responses, struct mosquitto *context, return MOSQ_ERR_INVAL; } - if(!strcasecmp(command, "getPluginInfo")){ - rc = broker__process_get_plugin_info(j_responses, context, aiter, correlation_data); + if(!strcasecmp(command, "listPlugins")){ + rc = broker__process_list_plugins(j_responses, context, aiter, correlation_data); }else if(!strcasecmp(command, "listListeners")){ rc = broker__process_list_listeners(j_responses, context, aiter, correlation_data); diff --git a/test/broker/17-control-list-plugins.py b/test/broker/17-control-list-plugins.py new file mode 100755 index 00000000..a0d64a7a --- /dev/null +++ b/test/broker/17-control-list-plugins.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 + +# Test $CONTROL/broker/v1 listListeners + +from mosq_test_helper import * +import json +import shutil + +def write_config(filename, port): + with open(filename, 'w') as f: + f.write("enable_control_api true\n") + f.write("allow_anonymous true\n") + f.write("listener %d\n" % (port)) + f.write("plugin c/auth_plugin_v5_control.so\n") + +def command_check(sock, command_payload, expected_response): + command_packet = mosq_test.gen_publish(topic="$CONTROL/broker/v1", qos=0, payload=json.dumps(command_payload)) + sock.send(command_packet) + response = json.loads(mosq_test.read_publish(sock)) + if response != expected_response: + print(expected_response) + print(response) + raise ValueError(response) + +def invalid_command_check(sock, command_payload, cmd_name, error_msg): + command_packet = mosq_test.gen_publish(topic="$CONTROL/broker/v1", qos=0, payload=command_payload) + sock.send(command_packet) + response = json.loads(mosq_test.read_publish(sock)) + expected_response = {'responses': [{'command': cmd_name, 'error': error_msg}]} + if response != expected_response: + print(expected_response) + print(response) + raise ValueError(response) + + + +port = mosq_test.get_port() +conf_file = os.path.basename(__file__).replace('.py', '.conf') +write_config(conf_file, port) + +cmd_success = {"commands":[{"command": "listPlugins", "correlationData": "m3CtYVnySLCOwnHzITSeowvgla0InV4G"}]} + +response_success = {'responses': [{'command': 'listPlugins', "correlationData": "m3CtYVnySLCOwnHzITSeowvgla0InV4G", 'data':{ + 'plugins':[ + { + 'name': 'test-plugin', + 'control-endpoints': ['$CONTROL/test/v1'] + } + ]}}]} + +rc = 1 +connect_packet = mosq_test.gen_connect("17-list-listeners") +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 2 +subscribe_packet = mosq_test.gen_subscribe(mid, "$CONTROL/broker/#", 0) +suback_packet = mosq_test.gen_suback(mid, 0) + +broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + +try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + invalid_command_check(sock, "not valid json", "Unknown command", "Payload not valid JSON") + invalid_command_check(sock, "{}", "Unknown command", "Invalid/missing commands") + + cmd = {"commands":["command"]} + invalid_command_check(sock, json.dumps(cmd), "Unknown command", "Command not an object") + + cmd = {"commands":[{}]} + invalid_command_check(sock, json.dumps(cmd), "Unknown command", "Missing command") + + cmd = {"commands":[{"command": "unknown command"}]} + invalid_command_check(sock, json.dumps(cmd), "unknown command", "Unknown command") + + cmd = {"commands":[{"command": "listListeners", "correlationData": True}]} + invalid_command_check(sock, json.dumps(cmd), "listListeners", "Invalid correlationData data type.") + + command_check(sock, cmd_success, response_success) + mosq_test.do_ping(sock) + + rc = 0 + + sock.close() +except mosq_test.TestError: + pass +finally: + os.remove(conf_file) + for f in ["17-list-listeners-mqtt.sock", "17-list-listeners-websockets.sock"]: + try: + os.remove(f) + except FileNotFoundError: + pass + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde.decode('utf-8')) + + +exit(rc) diff --git a/test/broker/Makefile b/test/broker/Makefile index 43a1b3ee..bf11eaf4 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -288,3 +288,4 @@ endif 17 : ./17-control-list-listeners.py + ./17-control-list-plugins.py diff --git a/test/broker/c/Makefile b/test/broker/c/Makefile index 31c374b4..2fa455ae 100644 --- a/test/broker/c/Makefile +++ b/test/broker/c/Makefile @@ -20,6 +20,7 @@ PLUGIN_SRC = \ auth_plugin_v4.c \ auth_plugin_v5.c \ auth_plugin_v5_handle_message.c \ + auth_plugin_v5_control.c \ plugin_control.c PLUGINS = ${PLUGIN_SRC:.c=.so} diff --git a/test/broker/c/auth_plugin_v5_control.c b/test/broker/c/auth_plugin_v5_control.c new file mode 100644 index 00000000..5c18c5bd --- /dev/null +++ b/test/broker/c/auth_plugin_v5_control.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include + +int mosquitto_auth_acl_check_v5(int event, void *event_data, void *user_data); +int mosquitto_auth_unpwd_check_v5(int event, void *event_data, void *user_data); + +static mosquitto_plugin_id_t *plg_id; + +MOSQUITTO_PLUGIN_DECLARE_VERSION(5); + +int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count) +{ + (void)user_data; + (void)auth_opts; + (void)auth_opt_count; + + plg_id = identifier; + + mosquitto_plugin_set_info(identifier, "test-plugin", NULL); + + mosquitto_callback_register(plg_id, MOSQ_EVT_ACL_CHECK, mosquitto_auth_acl_check_v5, NULL, NULL); + mosquitto_callback_register(plg_id, MOSQ_EVT_BASIC_AUTH, mosquitto_auth_unpwd_check_v5, NULL, NULL); + mosquitto_callback_register(plg_id, MOSQ_EVT_CONTROL, mosquitto_auth_unpwd_check_v5, "$CONTROL/test/v1", NULL); + + return MOSQ_ERR_SUCCESS; +} + +int mosquitto_plugin_cleanup(void *user_data, struct mosquitto_opt *auth_opts, int auth_opt_count) +{ + (void)user_data; + (void)auth_opts; + (void)auth_opt_count; + + mosquitto_callback_unregister(plg_id, MOSQ_EVT_ACL_CHECK, mosquitto_auth_acl_check_v5, NULL); + mosquitto_callback_unregister(plg_id, MOSQ_EVT_BASIC_AUTH, mosquitto_auth_unpwd_check_v5, NULL); + + return MOSQ_ERR_SUCCESS; +} + +int mosquitto_auth_acl_check_v5(int event, void *event_data, void *user_data) +{ + (void)event; + (void)event_data; + (void)user_data; + + return MOSQ_ERR_SUCCESS; +} + +int mosquitto_auth_unpwd_check_v5(int event, void *event_data, void *user_data) +{ + (void)event; + (void)event_data; + (void)user_data; + + return MOSQ_ERR_SUCCESS; +} diff --git a/test/broker/test.py b/test/broker/test.py index 8dd8cfff..bda92105 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -247,6 +247,7 @@ tests = [ (1, './16-config-parse-errors.py'), (4, './17-control-list-listeners.py'), + (1, './17-control-list-plugins.py'), ] ptest.run_tests(tests)