From 81c4e2b6ac4bf8581e371b30595caa0d40159776 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 25 Nov 2020 21:40:57 +0000 Subject: [PATCH] dynsec: Commit client auth tests. --- test/broker/14-dynsec-auth.py | 159 ++++++++++++++++++++++++++++++++++ test/broker/Makefile | 5 +- test/broker/test.py | 1 + 3 files changed, 163 insertions(+), 2 deletions(-) create mode 100755 test/broker/14-dynsec-auth.py diff --git a/test/broker/14-dynsec-auth.py b/test/broker/14-dynsec-auth.py new file mode 100755 index 00000000..478ac54e --- /dev/null +++ b/test/broker/14-dynsec-auth.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 + +from mosq_test_helper import * +import json +import shutil + +def write_config(filename, port): + with open(filename, 'w') as f: + f.write("listener %d\n" % (port)) + f.write("allow_anonymous true\n") + f.write("plugin ../../plugins/dynamic-security/mosquitto_dynamic_security.so\n") + f.write("plugin_opt_config_file %d/dynamic-security.json\n" % (port)) + +def command_check(sock, command_payload, expected_response): + command_packet = mosq_test.gen_publish(topic="$CONTROL/dynamic-security/v1", qos=0, payload=json.dumps(command_payload)) + sock.send(command_packet) + response = json.loads(mosq_test.read_publish(sock)) + if response != expected_response: + print(expected_response) + print(response) + raise ValueError(response) + + + +port = mosq_test.get_port() +conf_file = os.path.basename(__file__).replace('.py', '.conf') +write_config(conf_file, port) + +add_client_command_with_id = { "commands": [{ + "command": "createClient", "username": "user_one", + "password": "password", "clientid": "cid", + "correlationData": "2" }] +} +add_client_response_with_id = {'responses': [{'command': 'createClient', 'correlationData': '2'}]} + +add_client_command_without_id = { "commands": [{ + "command": "createClient", "username": "user_two", + "password": "asdfgh", + "correlationData": "3" }] +} +add_client_response_without_id = {'responses': [{'command': 'createClient', 'correlationData': '3'}]} + +# No password defined, this client should never be able to connect. +add_client_command_without_pw = { "commands": [{ + "command": "createClient", "username": "user_three", + "correlationData": "4" }] +} +add_client_response_without_pw = {'responses': [{'command': 'createClient', 'correlationData': '4'}]} + +rc = 1 +keepalive = 10 +connect_packet = mosq_test.gen_connect("ctrl-test", keepalive=keepalive, username="admin", password="admin") +connack_packet = mosq_test.gen_connack(rc=0) + +mid = 2 +subscribe_packet = mosq_test.gen_subscribe(mid, "$CONTROL/dynamic-security/#", 1) +suback_packet = mosq_test.gen_suback(mid, 1) + +# Success +connect_packet_with_id1 = mosq_test.gen_connect("cid", keepalive=keepalive, username="user_one", password="password", proto_ver=5) +connack_packet_with_id1 = mosq_test.gen_connack(rc=0, proto_ver=5) + +# Fail - bad client id +connect_packet_with_id2 = mosq_test.gen_connect("bad-cid", keepalive=keepalive, username="user_one", password="password", proto_ver=5) +connack_packet_with_id2 = mosq_test.gen_connack(rc=mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5, property_helper=False) + +# Fail - bad password +connect_packet_with_id3 = mosq_test.gen_connect("cid", keepalive=keepalive, username="user_one", password="ttt", proto_ver=5) +connack_packet_with_id3 = mosq_test.gen_connack(rc=mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5, property_helper=False) + +# Fail - no password +connect_packet_with_id4 = mosq_test.gen_connect("cid", keepalive=keepalive, username="user_one", proto_ver=5) +connack_packet_with_id4 = mosq_test.gen_connack(rc=mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5, property_helper=False) + +# Success +connect_packet_without_id1 = mosq_test.gen_connect("no-cid", keepalive=keepalive, username="user_two", password="asdfgh", proto_ver=5) +connack_packet_without_id1 = mosq_test.gen_connack(rc=0, proto_ver=5) + +# Fail - bad password +connect_packet_without_id2 = mosq_test.gen_connect("no-cid", keepalive=keepalive, username="user_two", password="pass", proto_ver=5) +connack_packet_without_id2 = mosq_test.gen_connack(rc=mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5, property_helper=False) + +# Fail - no password +connect_packet_without_id3 = mosq_test.gen_connect("no-cid", keepalive=keepalive, username="user_two", proto_ver=5) +connack_packet_without_id3 = mosq_test.gen_connack(rc=mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5, property_helper=False) + + +# Fail - bad password +connect_packet_without_pw1 = mosq_test.gen_connect("cid2", keepalive=keepalive, username="user_three", password="pass", proto_ver=5) +connack_packet_without_pw1 = mosq_test.gen_connack(rc=mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5, property_helper=False) + +# Fail - no password +connect_packet_without_pw2 = mosq_test.gen_connect("cid2", keepalive=keepalive, username="user_two", proto_ver=5) +connack_packet_without_pw2 = mosq_test.gen_connack(rc=mqtt5_rc.MQTT_RC_NOT_AUTHORIZED, proto_ver=5, property_helper=False) + +try: + os.mkdir(str(port)) + shutil.copyfile("dynamic-security-init.json", "%d/dynamic-security.json" % (port)) +except FileExistsError: + pass + +broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + +try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=5, port=port) + mosq_test.do_send_receive(sock, subscribe_packet, suback_packet, "suback") + + # Add client + command_check(sock, add_client_command_with_id, add_client_response_with_id) + command_check(sock, add_client_command_without_id, add_client_response_without_id) + command_check(sock, add_client_command_without_pw, add_client_response_without_pw) + + sock = mosq_test.do_client_connect(connect_packet_with_id1, connack_packet_with_id1, timeout=5, port=port, connack_error="with id 1") + sock.close() + + sock = mosq_test.do_client_connect(connect_packet_with_id2, connack_packet_with_id2, timeout=5, port=port, connack_error="with id 2") + sock.close() + + sock = mosq_test.do_client_connect(connect_packet_with_id3, connack_packet_with_id3, timeout=5, port=port, connack_error="with id 3") + sock.close() + + sock = mosq_test.do_client_connect(connect_packet_with_id4, connack_packet_with_id4, timeout=5, port=port, connack_error="with id 4") + sock.close() + + sock = mosq_test.do_client_connect(connect_packet_without_id1, connack_packet_without_id1, timeout=5, port=port, connack_error="without id 1") + sock.close() + + sock = mosq_test.do_client_connect(connect_packet_without_id2, connack_packet_without_id2, timeout=5, port=port, connack_error="without id 2") + sock.close() + + sock = mosq_test.do_client_connect(connect_packet_without_id3, connack_packet_without_id3, timeout=5, port=port, connack_error="without id 3") + sock.close() + + sock = mosq_test.do_client_connect(connect_packet_without_pw1, connack_packet_without_pw1, timeout=5, port=port, connack_error="without pw 1") + sock.close() + + sock = mosq_test.do_client_connect(connect_packet_without_pw2, connack_packet_without_pw2, timeout=5, port=port, connack_error="without pw 2") + sock.close() + + rc = 0 + + sock.close() +except mosq_test.TestError: + pass +finally: + os.remove(conf_file) + try: + os.remove(f"{port}/dynamic-security.json") + except FileNotFoundError: + pass + os.rmdir(f"{port}") + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde.decode('utf-8')) + + +exit(rc) diff --git a/test/broker/Makefile b/test/broker/Makefile index 9f6c79bd..4d7032f3 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -221,10 +221,11 @@ endif ./13-malformed-unsubscribe-v5.py 14 : + ./14-dynsec-auth.py ./14-dynsec-client.py + ./14-dynsec-disable-client.py ./14-dynsec-group.py - ./14-dynsec-role.py ./14-dynsec-modify-client.py ./14-dynsec-modify-group.py ./14-dynsec-modify-role.py - ./14-dynsec-disable-client.py + ./14-dynsec-role.py diff --git a/test/broker/test.py b/test/broker/test.py index 003f8551..7de3e527 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -189,6 +189,7 @@ tests = [ (1, './13-malformed-subscribe-v5.py'), (1, './13-malformed-unsubscribe-v5.py'), + (1, './14-dynsec-auth.py'), (1, './14-dynsec-client.py'), (1, './14-dynsec-group.py'), (1, './14-dynsec-role.py'),