Skip to content

Commit 0eba848

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 81a9385 commit 0eba848

File tree

16 files changed

+403
-17
lines changed

16 files changed

+403
-17
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
@@ -138,6 +138,8 @@ enum mosquitto_client_state {
138138
mosq_cs_authenticating = 20, /* Client has sent CONNECT but is still undergoing extended authentication */
139139
mosq_cs_reauthenticating = 21, /* Client is undergoing reauthentication and shouldn't do anything else until complete */
140140
mosq_cs_delayed_auth = 22, /* Client is awaiting an authentication result from a plugin */
141+
mosq_cs_delayed_ext_auth = 23, /* Client is awaiting an extended authentication result from a plugin */
142+
mosq_cs_delayed_ext_reauth = 24, /* Client is awaiting a reauthentication result from a plugin */
141143
};
142144

143145
enum mosquitto__protocol {
@@ -457,6 +459,7 @@ struct mosquitto {
457459
#ifdef WITH_BROKER
458460
UT_hash_handle hh_id;
459461
UT_hash_handle hh_sock;
462+
UT_hash_handle hh_id_delayed_auth;
460463
struct mosquitto *for_free_next;
461464
struct session_expiry_list *expiry_list_item;
462465
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: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,13 @@ void context__remove_from_by_id(struct mosquitto *context)
366366
return;
367367
}
368368

369+
if(context->in_by_id == true){
370+
HASH_FIND(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context_found);
371+
if(context_found){
372+
HASH_DELETE(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context_found);
373+
}
374+
}
375+
369376
if(context->in_by_id){
370377
HASH_FIND(hh_id, db.contexts_by_id, context->id, strlen(context->id), context_found);
371378
if(context_found == context){

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

@@ -139,6 +140,15 @@ int handle__auth(struct mosquitto *context)
139140
rc = send__auth(context, MQTT_RC_CONTINUE_AUTHENTICATION, auth_data_out, auth_data_out_len);
140141
SAFE_FREE(auth_data_out);
141142
return rc;
143+
}else if(rc == MOSQ_ERR_AUTH_DELAYED){
144+
SAFE_FREE(auth_data_out);
145+
if(context->state == mosq_cs_authenticating){
146+
mosquitto__set_state(context, mosq_cs_delayed_ext_auth);
147+
}else{
148+
mosquitto__set_state(context, mosq_cs_delayed_ext_reauth);
149+
}
150+
HASH_ADD_KEYPTR(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context);
151+
return MOSQ_ERR_SUCCESS;
142152
}else{
143153
SAFE_FREE(auth_data_out);
144154
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
@@ -1202,7 +1202,7 @@ int handle__connect(struct mosquitto *context)
12021202
}
12031203

12041204
/* Check for an existing delayed auth check, reject if present */
1205-
HASH_FIND(hh_id, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), found_context);
1205+
HASH_FIND(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), found_context);
12061206
if(found_context){
12071207
rc = MOSQ_ERR_UNKNOWN;
12081208
goto handle_connect_error;
@@ -1222,6 +1222,10 @@ int handle__connect(struct mosquitto *context)
12221222
rc = send__auth(context, MQTT_RC_CONTINUE_AUTHENTICATION, auth_data_out, auth_data_out_len);
12231223
SAFE_FREE(auth_data_out);
12241224
return rc;
1225+
}else if(rc == MOSQ_ERR_AUTH_DELAYED){
1226+
mosquitto__set_state(context, mosq_cs_delayed_ext_auth);
1227+
HASH_ADD_KEYPTR(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context);
1228+
return MOSQ_ERR_SUCCESS;
12251229
}else{
12261230
SAFE_FREE(auth_data_out);
12271231
will__clear(context);
@@ -1252,7 +1256,7 @@ int handle__connect(struct mosquitto *context)
12521256
break;
12531257
case MOSQ_ERR_AUTH_DELAYED:
12541258
mosquitto__set_state(context, mosq_cs_delayed_auth);
1255-
HASH_ADD_KEYPTR(hh_id, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context);
1259+
HASH_ADD_KEYPTR(hh_id_delayed_auth, db.contexts_by_id_delayed_auth, context->id, strlen(context->id), context);
12561260
return MOSQ_ERR_SUCCESS;
12571261
break;
12581262
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
@@ -865,9 +865,9 @@ BROKER_EXPORT void mosquitto_complete_basic_auth(const char *clientid, int resul
865865
return;
866866
}
867867

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

887887

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

0 commit comments

Comments
 (0)