Add %c and %u support to dynsec publish ACLs.

This commit is contained in:
Roger A. Light
2021-06-10 22:19:33 +01:00
parent 6502d6e5f4
commit 0cd2619401
10 changed files with 88 additions and 6 deletions
+3
View File
@@ -24,6 +24,9 @@ Broker:
using QoS 1 or 2 will receive the quota-exceeded reason code in the
corresponding PUBACK/PUBREC.
- MOSQ_EVT_TICK is now passed to plugins when `per_listener_settings` is true.
- The dynamic security plugin now supports `%c` and `%u` patterns for
substituting client id and username respectively, in publishClientSend and
publishClientReceive ACLs.
Client library:
- Add MOSQ_OPT_DISABLE_SOCKETPAIR to allow the disabling of the socketpair
+10 -2
View File
@@ -38,10 +38,14 @@ static int acl_check_publish_c_recv(struct mosquitto_evt_acl_check *ed, struct d
struct dynsec__rolelist *rolelist, *rolelist_tmp = NULL;
struct dynsec__acl *acl, *acl_tmp = NULL;
bool result;
const char *clientid, *username;
clientid = mosquitto_client_id(ed->client);
username = mosquitto_client_username(ed->client);
HASH_ITER(hh, base_rolelist, rolelist, rolelist_tmp){
HASH_ITER(hh, rolelist->role->acls.publish_c_recv, acl, acl_tmp){
mosquitto_topic_matches_sub(acl->topic, ed->topic, &result);
mosquitto_topic_matches_sub_with_pattern(acl->topic, ed->topic, clientid, username, &result);
if(result){
if(acl->allow){
return MOSQ_ERR_SUCCESS;
@@ -66,10 +70,14 @@ static int acl_check_publish_c_send(struct mosquitto_evt_acl_check *ed, struct d
struct dynsec__rolelist *rolelist, *rolelist_tmp = NULL;
struct dynsec__acl *acl, *acl_tmp = NULL;
bool result;
const char *clientid, *username;
clientid = mosquitto_client_id(ed->client);
username = mosquitto_client_username(ed->client);
HASH_ITER(hh, base_rolelist, rolelist, rolelist_tmp){
HASH_ITER(hh, rolelist->role->acls.publish_c_send, acl, acl_tmp){
mosquitto_topic_matches_sub(acl->topic, ed->topic, &result);
mosquitto_topic_matches_sub_with_pattern(acl->topic, ed->topic, clientid, username, &result);
if(result){
if(acl->allow){
return MOSQ_ERR_SUCCESS;
+1
View File
@@ -32,4 +32,5 @@ _mosquitto_set_username
_mosquitto_strdup
_mosquitto_sub_topic_check
_mosquitto_topic_matches_sub
_mosquitto_topic_matches_sub_with_pattern
_mosquitto_validate_utf8
+1
View File
@@ -33,5 +33,6 @@
mosquitto_strdup;
mosquitto_sub_topic_check;
mosquitto_topic_matches_sub;
mosquitto_topic_matches_sub_with_pattern;
mosquitto_validate_utf8;
};
+54
View File
@@ -44,6 +44,7 @@ add_client_group_role_command = {"commands":[
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "subscribePattern", "topic": "single-wildcard/+/topic", "allow": True },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "subscribePattern", "topic": "multilevel-wildcard/#", "allow": True },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "unsubscribeLiteral", "topic": "simple/topic", "allow": False },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "subscribePattern", "topic": "pattern/#", "allow": True },
{ "command": "addGroupClient", "groupname": "mygroup", "username": "user_one" }
]}
@@ -53,6 +54,7 @@ add_client_group_role_response = {'responses': [
{'command': 'addGroupRole'},
{'command': 'addRoleACL'}, {'command': 'addRoleACL'},
{'command': 'addRoleACL'}, {'command': 'addRoleACL'},
{'command': 'addRoleACL'},
{'command': 'addGroupClient'}
]}
@@ -61,11 +63,23 @@ add_publish_acl_command = {"commands":[
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientSend", "topic": "single-wildcard/deny/deny", "priority":10, "allow": False },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientSend", "topic": "single-wildcard/+/+", "allow": True },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientSend", "topic": "multilevel-wildcard/topic/#", "allow": True },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientSend", "topic": "pattern/%u/topic/#", "allow": True },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientSend", "topic": "pattern/%u/denied", "allow": False },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientSend", "topic": "pattern/%c/topic/#", "allow": True },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientSend", "topic": "pattern/%c/denied", "allow": False },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientReceive", "topic": "single-wildcard/bob/bob", "allow": False },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientReceive", "topic": "multilevel-wildcard/topic/topic/denied", "allow": False },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientReceive", "topic": "pattern/%u/topic/#", "allow": True },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientReceive", "topic": "pattern/%u/denied", "allow": False },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientReceive", "topic": "pattern/%c/topic/#", "allow": True },
{ "command": "addRoleACL", "rolename": "myrole", "acltype": "publishClientReceive", "topic": "pattern/%c/denied", "allow": False },
]}
add_publish_acl_response = {'responses': [
{'command': 'addRoleACL'}, {'command': 'addRoleACL'},
{'command': 'addRoleACL'}, {'command': 'addRoleACL'},
{'command': 'addRoleACL'}, {'command': 'addRoleACL'},
{'command': 'addRoleACL'}, {'command': 'addRoleACL'},
{'command': 'addRoleACL'}, {'command': 'addRoleACL'},
{'command': 'addRoleACL'}, {'command': 'addRoleACL'},
{'command': 'addRoleACL'}, {'command': 'addRoleACL'}
@@ -146,8 +160,30 @@ mid = 13
unsubscribe_multi_packet = mosq_test.gen_unsubscribe(mid, "multilevel-wildcard/topic/topic/#", proto_ver=5)
unsuback_multi_packet_success = mosq_test.gen_unsuback(mid, 0, proto_ver=5)
mid = 14
subscribe_pattern_packet = mosq_test.gen_subscribe(mid, "pattern/#", 0, proto_ver=5)
suback_pattern_packet = mosq_test.gen_suback(mid, 0, proto_ver=5)
disconnect_kick_packet = mosq_test.gen_disconnect(reason_code=mqtt5_rc.MQTT_RC_ADMINISTRATIVE_ACTION, proto_ver=5)
mid = 15
publish_u_pattern_packet = mosq_test.gen_publish(mid=mid, topic="pattern/user_one/topic", qos=1, proto_ver=5, payload="test")
puback_u_packet_success = mosq_test.gen_puback(mid=mid, proto_ver=5)
publish_u_pattern_packet_r = mosq_test.gen_publish(topic="pattern/user_one/topic", qos=0, proto_ver=5, payload="test")
mid = 16
publish_u_pattern_packet_denied = mosq_test.gen_publish(mid=mid, topic="pattern/user_one/denied", qos=1, proto_ver=5, payload="test")
puback_u_packet_denied = mosq_test.gen_puback(mid=mid, reason_code=mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5)
mid = 17
publish_c_pattern_packet = mosq_test.gen_publish(mid=mid, topic="pattern/user_one/topic", qos=1, proto_ver=5, payload="test")
puback_c_packet_success = mosq_test.gen_puback(mid=mid, proto_ver=5)
publish_c_pattern_packet_r = mosq_test.gen_publish(topic="pattern/user_one/topic", qos=0, proto_ver=5, payload="test")
mid = 18
publish_c_pattern_packet_denied = mosq_test.gen_publish(mid=mid, topic="pattern/user_one/denied", qos=1, proto_ver=5, payload="test")
puback_c_packet_denied = mosq_test.gen_puback(mid=mid, reason_code=mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5)
try:
os.mkdir(str(port))
shutil.copyfile("dynamic-security-init.json", "%d/dynamic-security.json" % (port))
@@ -230,6 +266,9 @@ try:
# Subscribe to "multilevel-wildcard/topic/topic/allowed" - this is now allowed
mosq_test.do_send_receive(csock, subscribe_multi_packet, suback_multi_packet_success, "suback multi 3")
# Subscribe to "pattern/#" - allowed
mosq_test.do_send_receive(csock, subscribe_pattern_packet, suback_pattern_packet, "suback")
# Publish to "simple/topic" - this is now allowed
csock.send(publish_simple_packet)
mosq_test.receive_unordered(csock, publish_simple_packet_r, puback_simple_packet_success, "puback simple 3 / publish r")
@@ -258,6 +297,21 @@ try:
# Multi unsubscribe should be allowed
mosq_test.do_send_receive(csock, unsubscribe_multi_packet, unsuback_multi_packet_success, "unsuback multi 1")
# Publish to "pattern/user_one/topic" - this is allowed
csock.send(publish_u_pattern_packet)
mosq_test.receive_unordered(csock, publish_u_pattern_packet_r, puback_u_packet_success, "puback pattern 1 / publish r")
# Publish to "pattern/user_one/denied" - this is not allowed
mosq_test.do_send_receive(csock, publish_u_pattern_packet_denied, puback_u_packet_denied, "puback pattern 2")
# Publish to "pattern/cid/topic" - this is allowed
csock.send(publish_c_pattern_packet)
mosq_test.receive_unordered(csock, publish_c_pattern_packet_r, puback_c_packet_success, "puback pattern 3 / publish r")
# Publish to "pattern/cid/denied" - this is not allowed
mosq_test.do_send_receive(csock, publish_c_pattern_packet_denied, puback_c_packet_denied, "puback pattern 4")
# Delete the role, client should be kicked
command_check(sock, delete_role_command, delete_role_response)
+1 -1
View File
@@ -144,7 +144,7 @@ connect_packet = mosq_test.gen_connect("ctrl-test", keepalive=keepalive, usernam
connack_packet = mosq_test.gen_connack(rc=0)
mid = 2
subscribe_packet = mosq_test.gen_subscribe(mid, "$CONTROL/#", 1)
subscribe_packet = mosq_test.gen_subscribe(mid, "$CONTROL/dynamic-security/#", 1)
suback_packet = mosq_test.gen_suback(mid, 1)
try:
+1 -1
View File
@@ -130,7 +130,7 @@ connect_packet = mosq_test.gen_connect("ctrl-test", keepalive=keepalive, usernam
connack_packet = mosq_test.gen_connack(rc=0)
mid = 2
subscribe_packet = mosq_test.gen_subscribe(mid, "$CONTROL/#", 1)
subscribe_packet = mosq_test.gen_subscribe(mid, "$CONTROL/dynamic-security/#", 1)
suback_packet = mosq_test.gen_suback(mid, 1)
try:
+1 -1
View File
@@ -111,7 +111,7 @@ connect_packet = mosq_test.gen_connect("ctrl-test", keepalive=keepalive, usernam
connack_packet = mosq_test.gen_connack(rc=0)
mid = 2
subscribe_packet = mosq_test.gen_subscribe(mid, "$CONTROL/#", 1)
subscribe_packet = mosq_test.gen_subscribe(mid, "$CONTROL/dynamic-security/#", 1)
suback_packet = mosq_test.gen_suback(mid, 1)
try:
+1 -1
View File
@@ -176,7 +176,7 @@ connect_packet = mosq_test.gen_connect("ctrl-test", keepalive=keepalive, usernam
connack_packet = mosq_test.gen_connack(rc=0)
mid = 2
subscribe_packet = mosq_test.gen_subscribe(mid, "$CONTROL/#", 1)
subscribe_packet = mosq_test.gen_subscribe(mid, "$CONTROL/dynamic-security/#", 1)
suback_packet = mosq_test.gen_suback(mid, 1)
try:
@@ -190,6 +190,21 @@ the ACL topic filter and the topic provided in the SUBSCRIBE or UNSUBSCRIBE
message. This means that setting a `subscribePattern` ACL with topic filter `#`
to deny would prevent matching devices from subscribing to any topic at all.
#### ACL pattern substitution
The `publishClientSend` and `publishClientReceive` ACL types can make use of
pattern substitution. This means that the strings `%c` and `%u` will be
replaced with the client id and username of the client being checked,
respectively. The pattern strings must be the only item in that level of
hierarchy, so the ACL `topic/%count` will not be considered as a pattern.
For example, with an ACL of `room/%c/temperature`, a client connecting with
client id `kitchen` would be allowed to use the topic
`room/kitchen/temperature` only.
If a client does not have a username, a pattern that includes `%u` will always
fail to match against that client.
#### Text name
This is an optional text field to give a human friendly name to this role.