Skip to content

Commit 41947a6

Browse files
committed
Support delayed auth with extended authorization
Adds a new mosquitto_complete_extended_auth plugin function. Signed-off-by: Nicholas Jackson <nickajacks1@gmail.com>
1 parent f02a985 commit 41947a6

File tree

16 files changed

+398
-19
lines changed

16 files changed

+398
-19
lines changed

include/mosquitto/broker.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,36 @@ mosq_EXPORT int mosquitto_broker_publish_copy(
909909
*/
910910
mosq_EXPORT void mosquitto_complete_basic_auth(const char *clientid, int result);
911911

912+
/* Function: mosquitto_complete_extended_auth
913+
*
914+
* Complete a delayed extended authentication request.
915+
*
916+
* Useful for plugins that subscribe to the MOSQ_EVT_EXT_AUTH_START and
917+
* MOSQ_EVT_EXT_AUTH_CONTINUE events. If your plugin makes authentication
918+
* requests that are not "instant", in particular if they communciate with an
919+
* external service, then instead of blocking for a reply and returning
920+
* MOSQ_ERR_SUCCESS, MOSQ_ERR_AUTH_CONTINUE, or MOSQ_ERR_AUTH, the plugin can
921+
* return MOSQ_ERR_AUTH_DELAYED. This means that the plugin is promising to
922+
* tell the broker the authentication result in the future. Once the plugin has
923+
* an answer, it should call `mosquitto_complete_extended_auth()`, passing the
924+
* client id, result, and any additional auth data. Note that it is possible to
925+
* pass MOSQ_ERR_AUTH_CONTINUE to procede with additional authentication steps.
926+
*
927+
* Parameters:
928+
* clientid - ID of the client being authenticated
929+
* result - authentication result. This will typically be
930+
* MOSQ_ERR_SUCCESS, MOSQ_ERR_AUTH_CONTINUE, or MOSQ_ERR_AUTH.
931+
* Other error codes can be used if more appropriate, and
932+
* the client connection will still be rejected. e.g.,
933+
* MOSQ_ERR_NOMEM.
934+
* auth_data_out - optional auth_data bytes. Mosquitto will free any data
935+
* passed here, so string literals for example are not valid.
936+
* May be NULL.
937+
* auth_data_out_len - auth data length in bytes. May be 0 if no data is sent.
938+
*
939+
*/
940+
mosq_EXPORT void mosquitto_complete_extended_auth(const char *clientid, int result, void *auth_data_out, uint16_t auth_data_out_len);
941+
912942

913943
/* Function: mosquitto_broker_node_id_set
914944
*

lib/mosquitto_internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ enum mosquitto_client_state {
133133
mosq_cs_authenticating = 20, /* Client has sent CONNECT but is still undergoing extended authentication */
134134
mosq_cs_reauthenticating = 21, /* Client is undergoing reauthentication and shouldn't do anything else until complete */
135135
mosq_cs_delayed_auth = 22, /* Client is awaiting an authentication result from a plugin */
136+
mosq_cs_delayed_ext_auth = 23, /* Client is awaiting an extended authentication result from a plugin */
137+
mosq_cs_delayed_ext_reauth = 24, /* Client is awaiting a reauthentication result from a plugin */
136138
};
137139

138140
enum mosquitto__protocol {
@@ -451,6 +453,7 @@ struct mosquitto {
451453
#ifdef WITH_BROKER
452454
UT_hash_handle hh_id;
453455
UT_hash_handle hh_sock;
456+
UT_hash_handle hh_id_delayed_auth;
454457
struct mosquitto *for_free_next;
455458
struct session_expiry_list *expiry_list_item;
456459
uint16_t remote_port;

plugins/examples/delayed-auth/mosquitto_delayed_auth.c

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ SPDX-License-Identifier: EPL-2.0 OR EDL-1.0
2020
* This is an example plugin showing how to carry out delayed authentication.
2121
* The "authentication" in this example makes no checks whatsoever, but delays
2222
* the response by 5 seconds, and randomly chooses whether it should succeed.
23+
* The example supports basic and extended authentication.
2324
*
2425
* Compile with:
2526
* gcc -I<path to mosquitto-repo/include> -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
3334

3435

3536
#include <limits.h>
37+
#include <mosquitto/broker.h>
3638
#include <stdbool.h>
3739
#include <stdio.h>
3840
#include <string.h>
@@ -54,6 +56,7 @@ struct client_list {
5456
UT_hash_handle hh;
5557
char *id;
5658
time_t request_time;
59+
bool basic_auth;
5760
};
5861

5962
static mosquitto_plugin_id_t *mosq_pid = NULL;
@@ -71,16 +74,9 @@ static bool authentication_check(struct client_list *client, time_t now)
7174
}
7275

7376

74-
static int basic_auth_callback(int event, void *event_data, void *userdata)
77+
static int start_auth(int event, const char *id)
7578
{
76-
struct mosquitto_evt_basic_auth *ed = event_data;
7779
static struct client_list *client;
78-
const char *id;
79-
80-
UNUSED(event);
81-
UNUSED(userdata);
82-
83-
id = mosquitto_client_id(ed->client);
8480

8581
HASH_FIND(hh, clients, id, strlen(id), client);
8682
if(client){
@@ -97,12 +93,47 @@ static int basic_auth_callback(int event, void *event_data, void *userdata)
9793
return MOSQ_ERR_NOMEM;
9894
}
9995
client->request_time = time(NULL);
100-
HASH_ADD_KEYPTR(hh, clients, client->id, strlen(client->id), client);
96+
if(event == MOSQ_EVT_BASIC_AUTH){
97+
mosquitto_log_printf(MOSQ_LOG_DEBUG, "Starting basic auth for %s at %ld", client->id, time(NULL));
98+
client->basic_auth = true;
99+
}else{
100+
mosquitto_log_printf(MOSQ_LOG_DEBUG, "Starting extended auth for %s at %ld", client->id, time(NULL));
101+
client->basic_auth = false;
102+
}
101103

102-
mosquitto_log_printf(MOSQ_LOG_DEBUG, "Starting auth for %s at %ld", client->id, time(NULL));
104+
HASH_ADD_KEYPTR(hh, clients, client->id, strlen(client->id), client);
103105
}
104106

105107
return MOSQ_ERR_AUTH_DELAYED;
108+
109+
}
110+
111+
112+
static int basic_auth_callback(int event, void *event_data, void *userdata)
113+
{
114+
struct mosquitto_evt_basic_auth *ed = event_data;
115+
const char *id;
116+
117+
UNUSED(event);
118+
UNUSED(userdata);
119+
120+
id = mosquitto_client_id(ed->client);
121+
122+
return start_auth(event, id);
123+
}
124+
125+
126+
static int extended_auth_callback(int event, void *event_data, void *userdata)
127+
{
128+
struct mosquitto_evt_extended_auth *ed = event_data;
129+
const char *id;
130+
131+
UNUSED(event);
132+
UNUSED(userdata);
133+
134+
id = mosquitto_client_id(ed->client);
135+
136+
return start_auth(event, id);
106137
}
107138

108139

@@ -128,9 +159,17 @@ static int tick_callback(int event, void *event_data, void *userdata)
128159
r = random() % 1000;
129160
#endif
130161
if(r > 740){
131-
mosquitto_complete_basic_auth(client->id, MOSQ_ERR_AUTH);
162+
if(client->basic_auth){
163+
mosquitto_complete_basic_auth(client->id, MOSQ_ERR_AUTH);
164+
}else{
165+
mosquitto_complete_extended_auth(client->id, MOSQ_ERR_AUTH, NULL, 0);
166+
}
132167
}else{
133-
mosquitto_complete_basic_auth(client->id, MOSQ_ERR_SUCCESS);
168+
if(client->basic_auth){
169+
mosquitto_complete_basic_auth(client->id, MOSQ_ERR_SUCCESS);
170+
}else{
171+
mosquitto_complete_extended_auth(client->id, MOSQ_ERR_SUCCESS, NULL, 0);
172+
}
134173
}
135174
mosquitto_log_printf(MOSQ_LOG_DEBUG, "Completing auth for %s at %ld", client->id, now);
136175
HASH_DELETE(hh, clients, client);
@@ -162,6 +201,10 @@ int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, s
162201
if(rc){
163202
return rc;
164203
}
204+
rc = mosquitto_callback_register(mosq_pid, MOSQ_EVT_EXT_AUTH_START, extended_auth_callback, NULL, NULL);
205+
if(rc){
206+
return rc;
207+
}
165208
rc = mosquitto_callback_register(mosq_pid, MOSQ_EVT_TICK, tick_callback, NULL, NULL);
166209
return rc;
167210
}

src/context.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,9 +354,9 @@ void context__remove_from_by_id(struct mosquitto *context)
354354
struct mosquitto *context_found;
355355

356356
if(context->in_by_id == true && context->id){
357-
HASH_FIND(hh_id, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context_found);
357+
HASH_FIND(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context_found);
358358
if(context_found){
359-
HASH_DELETE(hh_id, db.contexts_by_id_delayed_auth, context_found);
359+
HASH_DELETE(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context_found);
360360
}
361361

362362
HASH_FIND(hh_id, db.contexts_by_id, context->id, strlen(context->id), context_found);

src/handle_auth.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
1818

1919
#include "config.h"
2020

21+
#include <mosquitto/defs.h>
2122
#include <stdio.h>
2223
#include <string.h>
2324

@@ -125,6 +126,15 @@ int handle__auth(struct mosquitto *context)
125126
rc = send__auth(context, MQTT_RC_CONTINUE_AUTHENTICATION, auth_data_out, auth_data_out_len);
126127
SAFE_FREE(auth_data_out);
127128
return rc;
129+
}else if(rc == MOSQ_ERR_AUTH_DELAYED){
130+
SAFE_FREE(auth_data_out);
131+
if(context->state == mosq_cs_authenticating){
132+
mosquitto__set_state(context, mosq_cs_delayed_ext_auth);
133+
}else{
134+
mosquitto__set_state(context, mosq_cs_delayed_ext_reauth);
135+
}
136+
HASH_ADD_KEYPTR(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context);
137+
return MOSQ_ERR_SUCCESS;
128138
}else{
129139
SAFE_FREE(auth_data_out);
130140
if(context->state == mosq_cs_authenticating && context->will){

src/handle_connect.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,7 @@ int handle__connect(struct mosquitto *context)
11641164
}
11651165

11661166
/* Check for an existing delayed auth check, reject if present */
1167-
HASH_FIND(hh_id, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), found_context);
1167+
HASH_FIND(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), found_context);
11681168
if(found_context){
11691169
rc = MOSQ_ERR_UNKNOWN;
11701170
goto handle_connect_error;
@@ -1184,6 +1184,10 @@ int handle__connect(struct mosquitto *context)
11841184
rc = send__auth(context, MQTT_RC_CONTINUE_AUTHENTICATION, auth_data_out, auth_data_out_len);
11851185
SAFE_FREE(auth_data_out);
11861186
return rc;
1187+
}else if(rc == MOSQ_ERR_AUTH_DELAYED){
1188+
mosquitto__set_state(context, mosq_cs_delayed_ext_auth);
1189+
HASH_ADD_KEYPTR(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context);
1190+
return MOSQ_ERR_SUCCESS;
11871191
}else{
11881192
SAFE_FREE(auth_data_out);
11891193
will__clear(context);
@@ -1214,7 +1218,7 @@ int handle__connect(struct mosquitto *context)
12141218
break;
12151219
case MOSQ_ERR_AUTH_DELAYED:
12161220
mosquitto__set_state(context, mosq_cs_delayed_auth);
1217-
HASH_ADD_KEYPTR(hh_id, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context);
1221+
HASH_ADD_KEYPTR(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context);
12181222
return MOSQ_ERR_SUCCESS;
12191223
break;
12201224
case MOSQ_ERR_AUTH:

src/linker-aix.syms

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mosquitto_client_protocol_version
1818
mosquitto_client_sub_count
1919
mosquitto_client_username
2020
mosquitto_complete_basic_auth
21+
mosquitto_complete_extended_auth
2122
mosquitto_control_command_reply
2223
mosquitto_control_generic_callback
2324
mosquitto_control_send_response

src/linker-macosx.syms

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ _mosquitto_client_sub_count
1919
_mosquitto_client_username
2020
_mosquitto_client_will_set
2121
_mosquitto_complete_basic_auth
22+
_mosquitto_complete_extended_auth
2223
_mosquitto_control_command_reply
2324
_mosquitto_control_generic_callback
2425
_mosquitto_control_send_response

src/linker.syms

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
mosquitto_client_username;
2121
mosquitto_client_will_set;
2222
mosquitto_complete_basic_auth;
23+
mosquitto_complete_extended_auth;
2324
mosquitto_control_command_reply;
2425
mosquitto_control_generic_callback;
2526
mosquitto_control_send_response;

src/plugin_public.c

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -864,9 +864,9 @@ BROKER_EXPORT void mosquitto_complete_basic_auth(const char *clientid, int resul
864864
return;
865865
}
866866

867-
HASH_FIND(hh_id, db.contexts_by_id_delayed_auth, clientid, strlen(clientid), context);
868-
if(context){
869-
HASH_DELETE(hh_id, db.contexts_by_id_delayed_auth, context);
867+
HASH_FIND(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, clientid, strlen(clientid), context);
868+
if(context && context->state == mosq_cs_delayed_auth){
869+
HASH_DELETE(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context);
870870
if(result == MOSQ_ERR_SUCCESS){
871871
connect__on_authorised(context, NULL, 0);
872872
}else{
@@ -884,6 +884,64 @@ BROKER_EXPORT void mosquitto_complete_basic_auth(const char *clientid, int resul
884884
}
885885

886886

887+
BROKER_EXPORT void mosquitto_complete_extended_auth(const char *clientid, int result, void *auth_data_out, uint16_t auth_data_out_len)
888+
{
889+
struct mosquitto *context;
890+
891+
if(clientid == NULL){
892+
return;
893+
}
894+
895+
HASH_FIND(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, clientid, strlen(clientid), context);
896+
if(context && (context->state == mosq_cs_delayed_ext_auth || context->state == mosq_cs_delayed_ext_reauth)){
897+
HASH_DELETE(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context);
898+
if(result == MOSQ_ERR_SUCCESS){
899+
if(context->state == mosq_cs_delayed_ext_auth){
900+
connect__on_authorised(context, auth_data_out, auth_data_out_len);
901+
}else{
902+
mosquitto__set_state(context, mosq_cs_active);
903+
send__auth(context, MQTT_RC_SUCCESS, auth_data_out, auth_data_out_len);
904+
SAFE_FREE(auth_data_out);
905+
}
906+
}else if(result == MOSQ_ERR_AUTH_CONTINUE){
907+
if(context->state == mosq_cs_delayed_ext_auth){
908+
mosquitto__set_state(context, mosq_cs_authenticating);
909+
}else{
910+
mosquitto__set_state(context, mosq_cs_reauthenticating);
911+
}
912+
send__auth(context, MQTT_RC_CONTINUE_AUTHENTICATION, auth_data_out, auth_data_out_len);
913+
SAFE_FREE(auth_data_out);
914+
}else{
915+
SAFE_FREE(auth_data_out);
916+
if(context->state == mosq_cs_delayed_ext_auth && context->will){
917+
/* Free will without sending if this is our first authentication attempt */
918+
will__clear(context);
919+
}
920+
if(result == MOSQ_ERR_AUTH){
921+
if(context->state == mosq_cs_delayed_ext_auth){
922+
send__connack(context, 0, MQTT_RC_NOT_AUTHORIZED, NULL);
923+
mosquitto_FREE(context->id);
924+
}else{
925+
send__disconnect(context, MQTT_RC_NOT_AUTHORIZED, NULL);
926+
}
927+
}else if(result == MOSQ_ERR_NOT_SUPPORTED){
928+
/* Client has requested extended authentication, but we don't support it. */
929+
if(context->state == mosq_cs_delayed_ext_auth){
930+
send__connack(context, 0, MQTT_RC_BAD_AUTHENTICATION_METHOD, NULL);
931+
mosquitto_FREE(context->id);
932+
}else{
933+
send__disconnect(context, MQTT_RC_BAD_AUTHENTICATION_METHOD, NULL);
934+
}
935+
}else{
936+
if(context->state == mosq_cs_delayed_ext_auth){
937+
mosquitto_FREE(context->id);
938+
}
939+
}
940+
}
941+
}
942+
}
943+
944+
887945
BROKER_EXPORT int mosquitto_broker_node_id_set(uint16_t id)
888946
{
889947
if(id > 1023){

0 commit comments

Comments
 (0)