14-dynsec-default-access.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #!/usr/bin/env python3
  2. # This tests the default ACL type access behaviour for when no ACL matches.
  3. from mosq_test_helper import *
  4. import json
  5. import shutil
  6. def write_config(filename, port):
  7. with open(filename, 'w') as f:
  8. f.write("listener %d\n" % (port))
  9. f.write("allow_anonymous false\n")
  10. f.write("plugin ../../plugins/dynamic-security/mosquitto_dynamic_security.so\n")
  11. f.write("plugin_opt_config_file %d/dynamic-security.json\n" % (port))
  12. def command_check(sock, command_payload, expected_response):
  13. command_packet = mosq_test.gen_publish(topic="$CONTROL/dynamic-security/v1", qos=0, payload=json.dumps(command_payload))
  14. sock.send(command_packet)
  15. response = json.loads(mosq_test.read_publish(sock))
  16. if response != expected_response:
  17. print("Expected: %s" % (expected_response))
  18. print("Received: %s" % (response))
  19. raise ValueError(response)
  20. port = mosq_test.get_port()
  21. conf_file = os.path.basename(__file__).replace('.py', '.conf')
  22. write_config(conf_file, port)
  23. add_client_command = { "commands": [{
  24. "command": "createClient", "username": "user_one",
  25. "password": "password", "clientid": "cid",
  26. "correlationData": "2" }]
  27. }
  28. add_client_response = {'responses': [{'command': 'createClient', 'correlationData': '2'}]}
  29. get_access_command = { "commands": [{"command": "getDefaultACLAccess", "correlationData": "3" }]}
  30. get_access_response = {'responses': [
  31. {
  32. "command": "getDefaultACLAccess",
  33. 'data': {'acls': [
  34. {'acltype': 'publishClientSend', 'allow': False},
  35. {'acltype': 'publishClientReceive', 'allow': True},
  36. {'acltype': 'subscribe', 'allow': False},
  37. {'acltype': 'unsubscribe', 'allow': True}
  38. ]},
  39. "correlationData": "3"
  40. }]
  41. }
  42. allow_subscribe_command = { "commands": [
  43. {
  44. "command": "setDefaultACLAccess",
  45. "acls":[
  46. { "acltype": "subscribe", "allow": True }
  47. ],
  48. "correlationData": "4" }
  49. ]
  50. }
  51. allow_subscribe_response = {'responses': [{'command': 'setDefaultACLAccess', 'correlationData': '4'}]}
  52. allow_publish_send_command = { "commands": [
  53. {
  54. "command": "setDefaultACLAccess",
  55. "acls":[
  56. { "acltype": "publishClientSend", "allow": True }
  57. ],
  58. "correlationData": "5" }
  59. ]
  60. }
  61. allow_publish_send_response = {'responses': [{'command': 'setDefaultACLAccess', 'correlationData': '5'}]}
  62. allow_publish_recv_command = { "commands": [
  63. {
  64. "command": "setDefaultACLAccess",
  65. "acls":[
  66. { "acltype": "publishClientReceive", "allow": False }
  67. ],
  68. "correlationData": "6" }
  69. ]
  70. }
  71. allow_publish_recv_response = {'responses': [{'command': 'setDefaultACLAccess', 'correlationData': '6'}]}
  72. allow_unsubscribe_command = { "commands": [
  73. {
  74. "command": "setDefaultACLAccess",
  75. "acls":[
  76. { "acltype": "unsubscribe", "allow": False }
  77. ],
  78. "correlationData": "7" }
  79. ]
  80. }
  81. allow_unsubscribe_response = {'responses': [{'command': 'setDefaultACLAccess', 'correlationData': '7'}]}
  82. rc = 1
  83. keepalive = 10
  84. connect_packet_admin = mosq_test.gen_connect("ctrl-test", keepalive=keepalive, username="admin", password="admin")
  85. connack_packet_admin = mosq_test.gen_connack(rc=0)
  86. mid = 2
  87. subscribe_packet_admin = mosq_test.gen_subscribe(mid, "$CONTROL/dynamic-security/#", 1)
  88. suback_packet_admin = mosq_test.gen_suback(mid, 1)
  89. connect_packet = mosq_test.gen_connect("cid", keepalive=keepalive, username="user_one", password="password", proto_ver=5)
  90. connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
  91. mid = 3
  92. subscribe_packet = mosq_test.gen_subscribe(mid, "topic", 0, proto_ver=5)
  93. suback_packet_fail = mosq_test.gen_suback(mid, mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5)
  94. suback_packet_success = mosq_test.gen_suback(mid, 0, proto_ver=5)
  95. mid = 4
  96. unsubscribe_packet = mosq_test.gen_unsubscribe(mid, "topic", proto_ver=5)
  97. unsuback_packet_fail = mosq_test.gen_unsuback(mid, mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5)
  98. unsuback_packet_success = mosq_test.gen_unsuback(mid, proto_ver=5)
  99. mid = 5
  100. publish_packet = mosq_test.gen_publish(topic="topic", mid=mid, qos=1, payload="message", proto_ver=5)
  101. puback_packet_fail = mosq_test.gen_puback(mid, proto_ver=5, reason_code=mqtt5_rc.MQTT_RC_NOT_AUTHORIZED)
  102. puback_packet_success = mosq_test.gen_puback(mid, proto_ver=5)
  103. publish_packet_recv = mosq_test.gen_publish(topic="topic", qos=0, payload="message", proto_ver=5)
  104. try:
  105. os.mkdir(str(port))
  106. shutil.copyfile("dynamic-security-init.json", "%d/dynamic-security.json" % (port))
  107. except FileExistsError:
  108. pass
  109. broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port)
  110. try:
  111. sock = mosq_test.do_client_connect(connect_packet_admin, connack_packet_admin, timeout=5, port=port)
  112. mosq_test.do_send_receive(sock, subscribe_packet_admin, suback_packet_admin, "admin suback")
  113. # Add client
  114. command_check(sock, add_client_command, add_client_response)
  115. command_check(sock, get_access_command, get_access_response)
  116. csock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=5, port=port)
  117. # Subscribe should fail because default access is deny
  118. mosq_test.do_send_receive(csock, subscribe_packet, suback_packet_fail, "suback fail")
  119. # Set default subscribe access to allow
  120. command_check(sock, allow_subscribe_command, allow_subscribe_response)
  121. # Subscribe should succeed because default access is now allowed
  122. mosq_test.do_send_receive(csock, subscribe_packet, suback_packet_success, "suback success")
  123. # Publish should fail because publishClientSend default is denied
  124. mosq_test.do_send_receive(csock, publish_packet, puback_packet_fail, "puback fail")
  125. # Set default publish send access to allow
  126. command_check(sock, allow_publish_send_command, allow_publish_send_response)
  127. # Publish should now succeed because publishClientSend default is allow
  128. # We also receive the message because publishClientReceive default is allow.
  129. csock.send(publish_packet)
  130. mosq_test.receive_unordered(csock, puback_packet_success, publish_packet_recv, "puback success / publish recv")
  131. # Set default publish receive access to deny
  132. command_check(sock, allow_publish_recv_command, allow_publish_recv_response)
  133. # Publish should succeed because publishClientSend default is allow
  134. # We should *not* receive the publish because it has been disabled.
  135. mosq_test.do_send_receive(csock, publish_packet, puback_packet_success, "puback success")
  136. mosq_test.do_ping(csock)
  137. # Unsubscribe should succeed because default access is allowed
  138. mosq_test.do_send_receive(csock, unsubscribe_packet, unsuback_packet_success, "unsuback success")
  139. # Set default unsubscribe access to allow
  140. command_check(sock, allow_unsubscribe_command, allow_unsubscribe_response)
  141. # Subscribe should succeed because default access is allowed
  142. mosq_test.do_send_receive(csock, subscribe_packet, suback_packet_success, "suback success 2")
  143. # Unsubscribe should fail because default access is no longer allowed
  144. mosq_test.do_send_receive(csock, unsubscribe_packet, unsuback_packet_fail, "unsuback fail")
  145. csock.close()
  146. rc = 0
  147. sock.close()
  148. except mosq_test.TestError:
  149. pass
  150. finally:
  151. os.remove(conf_file)
  152. try:
  153. os.remove(f"{port}/dynamic-security.json")
  154. except FileNotFoundError:
  155. pass
  156. os.rmdir(f"{port}")
  157. broker.terminate()
  158. broker.wait()
  159. (stdo, stde) = broker.communicate()
  160. if rc:
  161. print(stde.decode('utf-8'))
  162. exit(rc)