diff --git a/include/mosquitto/broker.h b/include/mosquitto/broker.h index 9a4cd1f19c..5d520d966a 100644 --- a/include/mosquitto/broker.h +++ b/include/mosquitto/broker.h @@ -909,6 +909,36 @@ mosq_EXPORT int mosquitto_broker_publish_copy( */ mosq_EXPORT void mosquitto_complete_basic_auth(const char *clientid, int result); +/* Function: mosquitto_complete_extended_auth + * + * Complete a delayed extended authentication request. + * + * Useful for plugins that subscribe to the MOSQ_EVT_EXT_AUTH_START and + * MOSQ_EVT_EXT_AUTH_CONTINUE events. If your plugin makes authentication + * requests that are not "instant", in particular if they communciate with an + * external service, then instead of blocking for a reply and returning + * MOSQ_ERR_SUCCESS, MOSQ_ERR_AUTH_CONTINUE, or MOSQ_ERR_AUTH, the plugin can + * return MOSQ_ERR_AUTH_DELAYED. This means that the plugin is promising to + * tell the broker the authentication result in the future. Once the plugin has + * an answer, it should call `mosquitto_complete_extended_auth()`, passing the + * client id, result, and any additional auth data. Note that it is possible to + * pass MOSQ_ERR_AUTH_CONTINUE to procede with additional authentication steps. + * + * Parameters: + * clientid - ID of the client being authenticated + * result - authentication result. This will typically be + * MOSQ_ERR_SUCCESS, MOSQ_ERR_AUTH_CONTINUE, or MOSQ_ERR_AUTH. + * Other error codes can be used if more appropriate, and + * the client connection will still be rejected. e.g., + * MOSQ_ERR_NOMEM. + * auth_data_out - optional auth_data bytes. Mosquitto will free any data + * passed here, so string literals for example are not valid. + * May be NULL. + * auth_data_out_len - auth data length in bytes. May be 0 if no data is sent. + * + */ +mosq_EXPORT void mosquitto_complete_extended_auth(const char *clientid, int result, void *auth_data_out, uint16_t auth_data_out_len); + /* Function: mosquitto_broker_node_id_set * diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 0beaec3162..678450b850 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -138,6 +138,8 @@ enum mosquitto_client_state { mosq_cs_authenticating = 20, /* Client has sent CONNECT but is still undergoing extended authentication */ mosq_cs_reauthenticating = 21, /* Client is undergoing reauthentication and shouldn't do anything else until complete */ mosq_cs_delayed_auth = 22, /* Client is awaiting an authentication result from a plugin */ + mosq_cs_delayed_ext_auth = 23, /* Client is awaiting an extended authentication result from a plugin */ + mosq_cs_delayed_ext_reauth = 24, /* Client is awaiting a reauthentication result from a plugin */ }; enum mosquitto__protocol { @@ -457,6 +459,7 @@ struct mosquitto { #ifdef WITH_BROKER UT_hash_handle hh_id; UT_hash_handle hh_sock; + UT_hash_handle hh_id_delayed_auth; struct mosquitto *for_free_next; struct session_expiry_list *expiry_list_item; uint16_t remote_port; diff --git a/plugins/examples/delayed-auth/mosquitto_delayed_auth.c b/plugins/examples/delayed-auth/mosquitto_delayed_auth.c index 788177c11c..c214533737 100644 --- a/plugins/examples/delayed-auth/mosquitto_delayed_auth.c +++ b/plugins/examples/delayed-auth/mosquitto_delayed_auth.c @@ -20,6 +20,7 @@ SPDX-License-Identifier: EPL-2.0 OR EDL-1.0 * This is an example plugin showing how to carry out delayed authentication. * The "authentication" in this example makes no checks whatsoever, but delays * the response by 5 seconds, and randomly chooses whether it should succeed. + * The example supports basic and extended authentication. * * Compile with: * gcc -I -fPIC -shared mosquitto_delayed_auth.c -o mosquitto_delayed_auth.so @@ -33,6 +34,7 @@ SPDX-License-Identifier: EPL-2.0 OR EDL-1.0 #include +#include #include #include #include @@ -54,6 +56,7 @@ struct client_list { UT_hash_handle hh; char *id; time_t request_time; + bool basic_auth; }; static mosquitto_plugin_id_t *mosq_pid = NULL; @@ -71,16 +74,9 @@ static bool authentication_check(struct client_list *client, time_t now) } -static int basic_auth_callback(int event, void *event_data, void *userdata) +static int start_auth(int event, const char *id) { - struct mosquitto_evt_basic_auth *ed = event_data; static struct client_list *client; - const char *id; - - UNUSED(event); - UNUSED(userdata); - - id = mosquitto_client_id(ed->client); HASH_FIND(hh, clients, id, strlen(id), client); if(client){ @@ -97,12 +93,47 @@ static int basic_auth_callback(int event, void *event_data, void *userdata) return MOSQ_ERR_NOMEM; } client->request_time = time(NULL); - HASH_ADD_KEYPTR(hh, clients, client->id, strlen(client->id), client); + if(event == MOSQ_EVT_BASIC_AUTH){ + mosquitto_log_printf(MOSQ_LOG_DEBUG, "Starting basic auth for %s at %ld", client->id, time(NULL)); + client->basic_auth = true; + }else{ + mosquitto_log_printf(MOSQ_LOG_DEBUG, "Starting extended auth for %s at %ld", client->id, time(NULL)); + client->basic_auth = false; + } - mosquitto_log_printf(MOSQ_LOG_DEBUG, "Starting auth for %s at %ld", client->id, time(NULL)); + HASH_ADD_KEYPTR(hh, clients, client->id, strlen(client->id), client); } return MOSQ_ERR_AUTH_DELAYED; + +} + + +static int basic_auth_callback(int event, void *event_data, void *userdata) +{ + struct mosquitto_evt_basic_auth *ed = event_data; + const char *id; + + UNUSED(event); + UNUSED(userdata); + + id = mosquitto_client_id(ed->client); + + return start_auth(event, id); +} + + +static int extended_auth_callback(int event, void *event_data, void *userdata) +{ + struct mosquitto_evt_extended_auth *ed = event_data; + const char *id; + + UNUSED(event); + UNUSED(userdata); + + id = mosquitto_client_id(ed->client); + + return start_auth(event, id); } @@ -128,9 +159,17 @@ static int tick_callback(int event, void *event_data, void *userdata) r = random() % 1000; #endif if(r > 740){ - mosquitto_complete_basic_auth(client->id, MOSQ_ERR_AUTH); + if(client->basic_auth){ + mosquitto_complete_basic_auth(client->id, MOSQ_ERR_AUTH); + }else{ + mosquitto_complete_extended_auth(client->id, MOSQ_ERR_AUTH, NULL, 0); + } }else{ - mosquitto_complete_basic_auth(client->id, MOSQ_ERR_SUCCESS); + if(client->basic_auth){ + mosquitto_complete_basic_auth(client->id, MOSQ_ERR_SUCCESS); + }else{ + mosquitto_complete_extended_auth(client->id, MOSQ_ERR_SUCCESS, NULL, 0); + } } mosquitto_log_printf(MOSQ_LOG_DEBUG, "Completing auth for %s at %ld", client->id, now); HASH_DELETE(hh, clients, client); @@ -162,6 +201,10 @@ int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, s if(rc){ return rc; } + rc = mosquitto_callback_register(mosq_pid, MOSQ_EVT_EXT_AUTH_START, extended_auth_callback, NULL, NULL); + if(rc){ + return rc; + } rc = mosquitto_callback_register(mosq_pid, MOSQ_EVT_TICK, tick_callback, NULL, NULL); return rc; } diff --git a/src/context.c b/src/context.c index ca4784d918..2eabc16d92 100644 --- a/src/context.c +++ b/src/context.c @@ -366,6 +366,13 @@ void context__remove_from_by_id(struct mosquitto *context) return; } + if(context->in_by_id == true){ + HASH_FIND(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context_found); + if(context_found){ + HASH_DELETE(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context_found); + } + } + if(context->in_by_id){ HASH_FIND(hh_id, db.contexts_by_id, context->id, strlen(context->id), context_found); if(context_found == context){ diff --git a/src/handle_auth.c b/src/handle_auth.c index d8d1b505a9..00b7596679 100644 --- a/src/handle_auth.c +++ b/src/handle_auth.c @@ -18,6 +18,7 @@ SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause #include "config.h" +#include #include #include @@ -139,6 +140,15 @@ int handle__auth(struct mosquitto *context) rc = send__auth(context, MQTT_RC_CONTINUE_AUTHENTICATION, auth_data_out, auth_data_out_len); SAFE_FREE(auth_data_out); return rc; + }else if(rc == MOSQ_ERR_AUTH_DELAYED){ + SAFE_FREE(auth_data_out); + if(context->state == mosq_cs_authenticating){ + mosquitto__set_state(context, mosq_cs_delayed_ext_auth); + }else{ + mosquitto__set_state(context, mosq_cs_delayed_ext_reauth); + } + HASH_ADD_KEYPTR(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context); + return MOSQ_ERR_SUCCESS; }else{ SAFE_FREE(auth_data_out); if(context->state == mosq_cs_authenticating && context->will){ diff --git a/src/handle_connect.c b/src/handle_connect.c index 1d88132a87..7e196eb406 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -1202,7 +1202,7 @@ int handle__connect(struct mosquitto *context) } /* Check for an existing delayed auth check, reject if present */ - HASH_FIND(hh_id, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), found_context); + HASH_FIND(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), found_context); if(found_context){ rc = MOSQ_ERR_UNKNOWN; goto handle_connect_error; @@ -1222,6 +1222,10 @@ int handle__connect(struct mosquitto *context) rc = send__auth(context, MQTT_RC_CONTINUE_AUTHENTICATION, auth_data_out, auth_data_out_len); SAFE_FREE(auth_data_out); return rc; + }else if(rc == MOSQ_ERR_AUTH_DELAYED){ + mosquitto__set_state(context, mosq_cs_delayed_ext_auth); + HASH_ADD_KEYPTR(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context); + return MOSQ_ERR_SUCCESS; }else{ SAFE_FREE(auth_data_out); will__clear(context); @@ -1252,7 +1256,7 @@ int handle__connect(struct mosquitto *context) break; case MOSQ_ERR_AUTH_DELAYED: mosquitto__set_state(context, mosq_cs_delayed_auth); - HASH_ADD_KEYPTR(hh_id, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context); + HASH_ADD_KEYPTR(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context); return MOSQ_ERR_SUCCESS; break; case MOSQ_ERR_AUTH: diff --git a/src/linker-aix.syms b/src/linker-aix.syms index 7e8b6cd590..8afd7c1c02 100644 --- a/src/linker-aix.syms +++ b/src/linker-aix.syms @@ -18,6 +18,7 @@ mosquitto_client_protocol_version mosquitto_client_sub_count mosquitto_client_username mosquitto_complete_basic_auth +mosquitto_complete_extended_auth mosquitto_control_command_reply mosquitto_control_generic_callback mosquitto_control_send_response diff --git a/src/linker-macosx.syms b/src/linker-macosx.syms index 5f662204c2..0570fefc82 100644 --- a/src/linker-macosx.syms +++ b/src/linker-macosx.syms @@ -19,6 +19,7 @@ _mosquitto_client_sub_count _mosquitto_client_username _mosquitto_client_will_set _mosquitto_complete_basic_auth +_mosquitto_complete_extended_auth _mosquitto_control_command_reply _mosquitto_control_generic_callback _mosquitto_control_send_response diff --git a/src/linker.syms b/src/linker.syms index 178ad5ed8a..dc32f16521 100644 --- a/src/linker.syms +++ b/src/linker.syms @@ -20,6 +20,7 @@ mosquitto_client_username; mosquitto_client_will_set; mosquitto_complete_basic_auth; + mosquitto_complete_extended_auth; mosquitto_control_command_reply; mosquitto_control_generic_callback; mosquitto_control_send_response; diff --git a/src/plugin_public.c b/src/plugin_public.c index 769ad4c0b4..4a0eedbb50 100644 --- a/src/plugin_public.c +++ b/src/plugin_public.c @@ -865,9 +865,9 @@ BROKER_EXPORT void mosquitto_complete_basic_auth(const char *clientid, int resul return; } - HASH_FIND(hh_id, db.contexts_by_id_delayed_auth, clientid, strlen(clientid), context); - if(context){ - HASH_DELETE(hh_id, db.contexts_by_id_delayed_auth, context); + HASH_FIND(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, clientid, strlen(clientid), context); + if(context && context->state == mosq_cs_delayed_auth){ + HASH_DELETE(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context); if(result == MOSQ_ERR_SUCCESS){ connect__on_authorised(context, NULL, 0); }else{ @@ -885,6 +885,64 @@ BROKER_EXPORT void mosquitto_complete_basic_auth(const char *clientid, int resul } +BROKER_EXPORT void mosquitto_complete_extended_auth(const char *clientid, int result, void *auth_data_out, uint16_t auth_data_out_len) +{ + struct mosquitto *context; + + if(clientid == NULL){ + return; + } + + HASH_FIND(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, clientid, strlen(clientid), context); + if(context && (context->state == mosq_cs_delayed_ext_auth || context->state == mosq_cs_delayed_ext_reauth)){ + HASH_DELETE(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context); + if(result == MOSQ_ERR_SUCCESS){ + if(context->state == mosq_cs_delayed_ext_auth){ + connect__on_authorised(context, auth_data_out, auth_data_out_len); + }else{ + mosquitto__set_state(context, mosq_cs_active); + send__auth(context, MQTT_RC_SUCCESS, auth_data_out, auth_data_out_len); + SAFE_FREE(auth_data_out); + } + }else if(result == MOSQ_ERR_AUTH_CONTINUE){ + if(context->state == mosq_cs_delayed_ext_auth){ + mosquitto__set_state(context, mosq_cs_authenticating); + }else{ + mosquitto__set_state(context, mosq_cs_reauthenticating); + } + send__auth(context, MQTT_RC_CONTINUE_AUTHENTICATION, auth_data_out, auth_data_out_len); + SAFE_FREE(auth_data_out); + }else{ + SAFE_FREE(auth_data_out); + if(context->state == mosq_cs_delayed_ext_auth && context->will){ + /* Free will without sending if this is our first authentication attempt */ + will__clear(context); + } + if(result == MOSQ_ERR_AUTH){ + if(context->state == mosq_cs_delayed_ext_auth){ + send__connack(context, 0, MQTT_RC_NOT_AUTHORIZED, NULL); + mosquitto_FREE(context->id); + }else{ + send__disconnect(context, MQTT_RC_NOT_AUTHORIZED, NULL); + } + }else if(result == MOSQ_ERR_NOT_SUPPORTED){ + /* Client has requested extended authentication, but we don't support it. */ + if(context->state == mosq_cs_delayed_ext_auth){ + send__connack(context, 0, MQTT_RC_BAD_AUTHENTICATION_METHOD, NULL); + mosquitto_FREE(context->id); + }else{ + send__disconnect(context, MQTT_RC_BAD_AUTHENTICATION_METHOD, NULL); + } + }else{ + if(context->state == mosq_cs_delayed_ext_auth){ + mosquitto_FREE(context->id); + } + } + } + } +} + + BROKER_EXPORT int mosquitto_broker_node_id_set(uint16_t id) { if(id > 1023){ diff --git a/test/broker/09-plugin-delayed-extended-auth.py b/test/broker/09-plugin-delayed-extended-auth.py new file mode 100755 index 0000000000..4960356b66 --- /dev/null +++ b/test/broker/09-plugin-delayed-extended-auth.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 + +from mosq_test_helper import * +# Test for delayed multi-step extended auth. + +def write_config(filename, port): + with open(filename, 'w') as f: + f.write("listener %d\n" % (port)) + f.write("auth_plugin c/auth_plugin_delayed_extended.so\n") + +port = mosq_test.get_port() +conf_file = os.path.basename(__file__).replace('.py', '.conf') +write_config(conf_file, port) + +rc = 1 + +props = mqtt5_props.gen_string_prop(mqtt5_props.AUTHENTICATION_METHOD, "delayed-auth") +props += mqtt5_props.gen_string_prop(mqtt5_props.AUTHENTICATION_DATA, "good-start") +connect_packet = mosq_test.gen_connect("client-params-test", proto_ver=5, properties=props) + +# Server to client +props = mqtt5_props.gen_string_prop(mqtt5_props.AUTHENTICATION_METHOD, "delayed-auth") +props += mqtt5_props.gen_string_prop(mqtt5_props.AUTHENTICATION_DATA, "good-middle") +auth1_packet = mosq_test.gen_auth(reason_code=mqtt5_rc.CONTINUE_AUTHENTICATION, properties=props) + +# Client to server +props = mqtt5_props.gen_string_prop(mqtt5_props.AUTHENTICATION_METHOD, "delayed-auth") +props += mqtt5_props.gen_string_prop(mqtt5_props.AUTHENTICATION_DATA, "good-finish") +auth2_packet = mosq_test.gen_auth(reason_code=mqtt5_rc.CONTINUE_AUTHENTICATION, properties=props) + +props = mqtt5_props.gen_string_prop(mqtt5_props.AUTHENTICATION_METHOD, "delayed-auth") +connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5, properties=props) + + +broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + +try: + sock = mosq_test.do_client_connect(connect_packet, auth1_packet, timeout=20, port=port, connack_error="auth1") + mosq_test.do_send_receive(sock, auth2_packet, connack_packet) + + rc = 0 + + sock.close() +except mosq_test.TestError: + pass +finally: + os.remove(conf_file) + broker.terminate() + if mosq_test.wait_for_subprocess(broker): + print("broker not terminated") + if rc == 0: rc=1 + (stdo, stde) = broker.communicate() + if rc: + print(stde.decode('utf-8')) + + +exit(rc) + diff --git a/test/broker/Makefile b/test/broker/Makefile index ef62f26b36..48ce95b9fe 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -217,6 +217,7 @@ endif ./09-plugin-bad.py ./09-plugin-change-id.py ./09-plugin-delayed-auth.py + ./09-plugin-delayed-extended-auth.py ./09-plugin-evt-client-offline.py ./09-plugin-evt-message-in.py ./09-plugin-evt-message-out.py diff --git a/test/broker/c/CMakeLists.txt b/test/broker/c/CMakeLists.txt index 7647f9077b..6dab771df6 100644 --- a/test/broker/c/CMakeLists.txt +++ b/test/broker/c/CMakeLists.txt @@ -4,6 +4,7 @@ set(PLUGINS auth_plugin_acl_sub_denied auth_plugin_context_params auth_plugin_delayed + auth_plugin_delayed_extended auth_plugin_extended_multiple auth_plugin_extended_reauth auth_plugin_extended_single diff --git a/test/broker/c/Makefile b/test/broker/c/Makefile index 53d02d60d5..636b8772e9 100644 --- a/test/broker/c/Makefile +++ b/test/broker/c/Makefile @@ -13,6 +13,7 @@ PLUGIN_SRC = \ auth_plugin_acl_sub_denied.c \ auth_plugin_context_params.c \ auth_plugin_delayed.c \ + auth_plugin_delayed_extended.c \ auth_plugin_extended_multiple.c \ auth_plugin_extended_reauth.c \ auth_plugin_extended_single.c \ diff --git a/test/broker/c/auth_plugin_delayed_extended.c b/test/broker/c/auth_plugin_delayed_extended.c new file mode 100644 index 0000000000..d73a66ce56 --- /dev/null +++ b/test/broker/c/auth_plugin_delayed_extended.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include + +static int tick_callback(int event, void *event_data, void *user_data); +static int ext_auth_start_callback(int event, void *event_data, void *user_data); +static int ext_auth_continue_callback(int event, void *event_data, void *user_data); +static int stash_auth_info(struct mosquitto_evt_extended_auth *ed); + +static mosquitto_plugin_id_t *plg_id; + +static char *clientid = NULL; +static char *authmethod = NULL; +static void *authdata = NULL; +static uint16_t data_len = 0; +static int step = -1; +static int auth_delay = -1; + +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_callback_register(plg_id, MOSQ_EVT_TICK, tick_callback, NULL, NULL); + mosquitto_callback_register(plg_id, MOSQ_EVT_EXT_AUTH_START, ext_auth_start_callback, NULL, NULL); + mosquitto_callback_register(plg_id, MOSQ_EVT_EXT_AUTH_CONTINUE, ext_auth_continue_callback, NULL, 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; + + free(authmethod); + free(authdata); + free(clientid); + + mosquitto_callback_unregister(plg_id, MOSQ_EVT_EXT_AUTH_CONTINUE, ext_auth_continue_callback, NULL); + mosquitto_callback_unregister(plg_id, MOSQ_EVT_EXT_AUTH_START, ext_auth_start_callback, NULL); + mosquitto_callback_unregister(plg_id, MOSQ_EVT_TICK, tick_callback, NULL); + + return MOSQ_ERR_SUCCESS; +} + + +static int tick_callback(int event, void *event_data, void *user_data) +{ + struct mosquitto_evt_tick *ed = event_data; + + (void)user_data; + + if(event != MOSQ_EVT_TICK){ + abort(); + } + + if(auth_delay == 0){ + if(step == 1){ + if(clientid && authmethod && authdata + && !strcmp(authmethod, "delayed-auth") && !memcmp(authdata, "good-start", data_len)){ + void *respdata = strdup("good-middle"); + mosquitto_complete_extended_auth(clientid, MOSQ_ERR_AUTH_CONTINUE, respdata, strlen("good-middle")); + }else{ + mosquitto_complete_extended_auth(clientid, MOSQ_ERR_AUTH, NULL, 0); + } + }else if(step == 2){ + if(clientid && authmethod && authdata + && !strcmp(authmethod, "delayed-auth") && !memcmp(authdata, "good-finish", data_len)){ + mosquitto_complete_extended_auth(clientid, MOSQ_ERR_SUCCESS, NULL, 0); + }else{ + mosquitto_complete_extended_auth(clientid, MOSQ_ERR_AUTH, NULL, 0); + } + step = -1; + } + free(authmethod); + free(authdata); + free(clientid); + authmethod = NULL; + authdata = NULL; + clientid = NULL; + }else if(auth_delay > 0){ + auth_delay--; + } + + /* fast turn around for quick testing */ + ed->next_ms = 100; + + return MOSQ_ERR_SUCCESS; +} + + +static int ext_auth_start_callback(int event, void *event_data, void *user_data) +{ + struct mosquitto_evt_extended_auth *ed = event_data; + + (void)event; + (void)user_data; + + int rc = stash_auth_info(ed); + if(rc){ + return rc; + } + + /* Delay for arbitrary 10 ticks */ + auth_delay = 10; + step = 1; + + return MOSQ_ERR_AUTH_DELAYED; +} + + +static int ext_auth_continue_callback(int event, void *event_data, void *user_data) +{ + struct mosquitto_evt_extended_auth *ed = event_data; + + (void)event; + (void)user_data; + + int rc = stash_auth_info(ed); + if(rc){ + return rc; + } + + /* Delay for arbitrary 10 ticks */ + auth_delay = 10; + step = 2; + + return MOSQ_ERR_AUTH_DELAYED; +} + + +static int stash_auth_info(struct mosquitto_evt_extended_auth *ed) +{ + free(authmethod); + free(authdata); + free(clientid); + + if(ed->auth_method){ + authmethod = strdup(ed->auth_method); + } + if(ed->data_in){ + data_len = ed->data_in_len; + authdata = malloc(ed->data_in_len); + if(!authdata){ + return MOSQ_ERR_NOMEM; + } + memcpy(authdata, ed->data_in, ed->data_in_len); + } + clientid = strdup(mosquitto_client_id(ed->client)); + + return MOSQ_ERR_SUCCESS; +} + + diff --git a/test/broker/test.py b/test/broker/test.py index 7ec315003c..1d166af950 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -196,6 +196,7 @@ (1, './09-plugin-evt-tick.py'), (1, './09-plugin-evt-unsubscribe.py'), (1, './09-plugin-delayed-auth.py'), + (1, './09-plugin-delayed-extended-auth.py'), (3, './09-plugin-load.py'), (1, './09-plugin-publish.py'), (1, './09-plugin-unsupported.py'),