From 7ccf4c44fd0fb8a45fb8f33839d07a8d48c9da18 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 27 Nov 2020 14:35:07 +0000 Subject: [PATCH] dynsec: Tests for invalid client command input. --- test/broker/14-dynsec-client-invalid.py | 462 ++++++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/test.py | 1 + 3 files changed, 464 insertions(+) create mode 100755 test/broker/14-dynsec-client-invalid.py diff --git a/test/broker/14-dynsec-client-invalid.py b/test/broker/14-dynsec-client-invalid.py new file mode 100755 index 00000000..587c4116 --- /dev/null +++ b/test/broker/14-dynsec-client-invalid.py @@ -0,0 +1,462 @@ +#!/usr/bin/env python3 + +# Check invalid inputs for client commands + +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, msg=""): + 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) + if msg != "": + print(msg) + raise ValueError(response) + + + +port = mosq_test.get_port() +conf_file = os.path.basename(__file__).replace('.py', '.conf') +write_config(conf_file, port) + +# ========================================================================== +# Create client +# ========================================================================== + +# No username +create_client1_command = { 'commands': [{'command': 'createClient' }] } +create_client1_response = {'responses': [{'command': 'createClient', 'error': 'Invalid/missing username'}]} + +# Username not a string +create_client2_command = { 'commands': [{'command': 'createClient', 'username': 5 }] } +create_client2_response = {'responses': [{'command': 'createClient', 'error': 'Invalid/missing username'}]} + +# Username not UTF-8 +#create_client3_command = { 'commands': [{'command': 'createClient', 'username': }] } +#create_client3_response = {'responses': [{'command': 'createClient', 'error': 'Invalid/missing username'}]} + +# Password not a string +create_client4_command = { 'commands': [{'command': 'createClient', 'username': 'user', 'password':5 }] } +create_client4_response = {'responses': [{'command': 'createClient', 'error': 'Invalid/missing password'}]} + +# Client id not a string +create_client5_command = { 'commands': [{'command': 'createClient', 'username': 'user', 'password':'5', 'clientid':5}] } +create_client5_response = {'responses': [{'command': 'createClient', 'error': 'Invalid/missing client id'}]} + +# Text name not a string +create_client6_command = { 'commands': [{'command': 'createClient', 'username': 'user', 'password':'5', 'textname':5}] } +create_client6_response = {'responses': [{'command': 'createClient', 'error': 'Invalid/missing textname'}]} + +# Text description not a string +create_client7_command = { 'commands': [{'command': 'createClient', 'username': 'user', 'password':'5', 'textdescription':5}] } +create_client7_response = {'responses': [{'command': 'createClient', 'error': 'Invalid/missing textdescription'}]} + +# Client already exists +create_client8_command = { 'commands': [{'command': 'createClient', 'username': 'admin', 'password':'5'}]} +create_client8_response = {'responses': [{'command': 'createClient', 'error': 'Client already exists'}]} + +# Role not found +create_client9_command = { 'commands': [{'command': 'createClient', 'username': 'user', 'password':'5', 'roles':[{'rolename':'notfound'}]}] } +create_client9_response = {'responses': [{'command': 'createClient', 'error': 'Role not found'}]} + +# Group not found +create_client10_command = { 'commands': [{'command': 'createClient', 'username': 'user', 'password':'5', 'groups':[{'groupname':'notfound'}]}] } +create_client10_response = {'responses': [{'command': 'createClient', 'error': 'Group not found'}]} + + +# ========================================================================== +# Delete client +# ========================================================================== + +# No username +delete_client1_command = { 'commands': [{'command': 'deleteClient'}]} +delete_client1_response = {'responses': [{'command': 'deleteClient', 'error': 'Invalid/missing username'}]} + +# Username not a string +delete_client2_command = { 'commands': [{'command': 'deleteClient', 'username':5}]} +delete_client2_response = {'responses': [{'command': 'deleteClient', 'error': 'Invalid/missing username'}]} + +# Username not UTF-8 +#delete_client3_command = { 'commands': [{'command': 'deleteClient', 'username':5}]} +#delete_client3_response = {'responses': [{'command': 'deleteClient', 'error': 'Invalid/missing username'}]} + +# Client not found +delete_client4_command = { 'commands': [{'command': 'deleteClient', 'username':'notfound'}]} +delete_client4_response = {'responses': [{'command': 'deleteClient', 'error': 'Client not found'}]} + +# ========================================================================== +# Disable client +# ========================================================================== + +# No username +disable_client1_command = { 'commands': [{'command': 'disableClient'}]} +disable_client1_response = {'responses': [{'command': 'disableClient', 'error': 'Invalid/missing username'}]} + +# Username not a string +disable_client2_command = { 'commands': [{'command': 'disableClient', 'username':5}]} +disable_client2_response = {'responses': [{'command': 'disableClient', 'error': 'Invalid/missing username'}]} + +# Username not UTF-8 +#disable_client3_command = { 'commands': [{'command': 'disableClient', 'username':5}]} +#disable_client3_response = {'responses': [{'command': 'disableClient', 'error': 'Invalid/missing username'}]} + +# Client not found +disable_client4_command = { 'commands': [{'command': 'disableClient', 'username':'notfound'}]} +disable_client4_response = {'responses': [{'command': 'disableClient', 'error': 'Client not found'}]} + + +# ========================================================================== +# Enable client +# ========================================================================== + +# No username +enable_client1_command = { 'commands': [{'command': 'enableClient'}]} +enable_client1_response = {'responses': [{'command': 'enableClient', 'error': 'Invalid/missing username'}]} + +# Username not a string +enable_client2_command = { 'commands': [{'command': 'enableClient', 'username':5}]} +enable_client2_response = {'responses': [{'command': 'enableClient', 'error': 'Invalid/missing username'}]} + +# Username not UTF-8 +#enable_client3_command = { 'commands': [{'command': 'enableClient', 'username':5}]} +#enable_client3_response = {'responses': [{'command': 'enableClient', 'error': 'Invalid/missing username'}]} + +# Client not found +enable_client4_command = { 'commands': [{'command': 'enableClient', 'username':'notfound'}]} +enable_client4_response = {'responses': [{'command': 'enableClient', 'error': 'Client not found'}]} + + +# ========================================================================== +# Set client id +# ========================================================================== + +# No username +set_client_id1_command = { 'commands': [{'command': 'setClientId'}]} +set_client_id1_response = {'responses': [{'command': 'setClientId', 'error': 'Invalid/missing username'}]} + +# Username not a string +set_client_id2_command = { 'commands': [{'command': 'setClientId', 'username':5}]} +set_client_id2_response = {'responses': [{'command': 'setClientId', 'error': 'Invalid/missing username'}]} + +# Username not UTF-8 +#set_client_id3_command = { 'commands': [{'command': 'setClientId', 'username':5}]} +#set_client_id3_response = {'responses': [{'command': 'setClientId', 'error': 'Invalid/missing username'}]} + +# No client id +set_client_id4_command = { 'commands': [{'command': 'setClientId', 'username':'user'}]} +set_client_id4_response = {'responses': [{'command': 'setClientId', 'error': 'Client not found'}]} + +# Client id not a string +set_client_id5_command = { 'commands': [{'command': 'setClientId', 'username':'user', 'clientid':5}]} +set_client_id5_response = {'responses': [{'command': 'setClientId', 'error': 'Invalid/missing client ID'}]} + +# Client id not UTF-8 +#set_client_id6_command = { 'commands': [{'command': 'setClientPassword', 'username':'user', 'clientid':5}]} +#set_client_id6_response = {'responses': [{'command': 'setClientPassword', 'error': 'Invalid/missing clientid'}]} + +# Client not found +set_client_id7_command = { 'commands': [{'command': 'setClientId', 'username':'notfound', 'clientid':'newid'}]} +set_client_id7_response = {'responses': [{'command': 'setClientId', 'error': 'Client not found'}]} + + +# ========================================================================== +# Set password +# ========================================================================== + +# No username +set_password1_command = { 'commands': [{'command': 'setClientPassword'}]} +set_password1_response = {'responses': [{'command': 'setClientPassword', 'error': 'Invalid/missing username'}]} + +# Username not a string +set_password2_command = { 'commands': [{'command': 'setClientPassword', 'username':5}]} +set_password2_response = {'responses': [{'command': 'setClientPassword', 'error': 'Invalid/missing username'}]} + +# Username not UTF-8 +#set_password3_command = { 'commands': [{'command': 'setClientPassword', 'username':5}]} +#set_password3_response = {'responses': [{'command': 'setClientPassword', 'error': 'Invalid/missing username'}]} + +# No password +set_password4_command = { 'commands': [{'command': 'setClientPassword', 'username':'user'}]} +set_password4_response = {'responses': [{'command': 'setClientPassword', 'error': 'Invalid/missing password'}]} + +# password not a string +set_password5_command = { 'commands': [{'command': 'setClientPassword', 'username':'user', 'password':5}]} +set_password5_response = {'responses': [{'command': 'setClientPassword', 'error': 'Invalid/missing password'}]} + +# password is empty +set_password6_command = { 'commands': [{'command': 'setClientPassword', 'username':'user', 'password':''}]} +set_password6_response = {'responses': [{'command': 'setClientPassword', 'error': 'Empty password is not allowed'}]} + +# Client not found +set_password7_command = { 'commands': [{'command': 'setClientPassword', 'username':'notfound', 'password':'newpw'}]} +set_password7_response = {'responses': [{'command': 'setClientPassword', 'error': 'Client not found'}]} + + +# ========================================================================== +# Get client +# ========================================================================== + +# No username +get_client1_command = { 'commands': [{'command': 'getClient'}]} +get_client1_response = {'responses': [{'command': 'getClient', 'error': 'Invalid/missing username'}]} + +# Username not a string +get_client2_command = { 'commands': [{'command': 'getClient', 'username':5}]} +get_client2_response = {'responses': [{'command': 'getClient', 'error': 'Invalid/missing username'}]} + +# Username not UTF-8 +#get_client3_command = { 'commands': [{'command': 'getClient', 'username':5}]} +#get_client3_response = {'responses': [{'command': 'getClient', 'error': 'Invalid/missing username'}]} + +# Client not found +get_client4_command = { 'commands': [{'command': 'getClient', 'username':'notfound'}]} +get_client4_response = {'responses': [{'command': 'getClient', 'error': 'Client not found'}]} + + +# ========================================================================== +# Add role +# ========================================================================== + +# No username +add_role1_command = { 'commands': [{'command': 'addClientRole'}]} +add_role1_response = {'responses': [{'command': 'addClientRole', 'error': 'Invalid/missing username'}]} + +# Username not a string +add_role2_command = { 'commands': [{'command': 'addClientRole', 'username':5}]} +add_role2_response = {'responses': [{'command': 'addClientRole', 'error': 'Invalid/missing username'}]} + +# Username not UTF-8 +#add_role3_command = { 'commands': [{'command': 'addClientRole', 'username':5}]} +#add_role3_response = {'responses': [{'command': 'addClientRole', 'error': 'Invalid/missing username'}]} + +# No rolename +add_role4_command = { 'commands': [{'command': 'addClientRole', 'username':'user'}]} +add_role4_response = {'responses': [{'command': 'addClientRole', 'error': 'Invalid/missing rolename'}]} + +# rolename not a string +add_role5_command = { 'commands': [{'command': 'addClientRole', 'username':'user', 'rolename':5}]} +add_role5_response = {'responses': [{'command': 'addClientRole', 'error': 'Invalid/missing rolename'}]} + +# rolename not UTF-8 +#add_role6_command = { 'commands': [{'command': 'addClientRole', 'username':'user'}]} +#add_role6_response = {'responses': [{'command': 'addClientRole', 'error': 'Invalid/missing rolename'}]} + +# Client not found +add_role7_command = { 'commands': [{'command': 'addClientRole', 'username':'notfound', 'rolename':'notfound'}]} +add_role7_response = {'responses': [{'command': 'addClientRole', 'error': 'Client not found'}]} + +# Role not found +add_role8_command = { 'commands': [{'command': 'addClientRole', 'username':'admin', 'rolename':'notfound'}]} +add_role8_response = {'responses': [{'command': 'addClientRole', 'error': 'Role not found'}]} + + +# ========================================================================== +# Remove role +# ========================================================================== + +# No username +remove_role1_command = { 'commands': [{'command': 'removeClientRole'}]} +remove_role1_response = {'responses': [{'command': 'removeClientRole', 'error': 'Invalid/missing username'}]} + +# Username not a string +remove_role2_command = { 'commands': [{'command': 'removeClientRole', 'username':5}]} +remove_role2_response = {'responses': [{'command': 'removeClientRole', 'error': 'Invalid/missing username'}]} + +# Username not UTF-8 +#remove_role3_command = { 'commands': [{'command': 'removeClientRole', 'username':5}]} +#remove_role3_response = {'responses': [{'command': 'removeClientRole', 'error': 'Invalid/missing username'}]} + +# No rolename +remove_role4_command = { 'commands': [{'command': 'removeClientRole', 'username':'user'}]} +remove_role4_response = {'responses': [{'command': 'removeClientRole', 'error': 'Invalid/missing rolename'}]} + +# rolename not a string +remove_role5_command = { 'commands': [{'command': 'removeClientRole', 'username':'user', 'rolename':5}]} +remove_role5_response = {'responses': [{'command': 'removeClientRole', 'error': 'Invalid/missing rolename'}]} + +# rolename not UTF-8 +#remove_role6_command = { 'commands': [{'command': 'removeClientRole', 'username':'user'}]} +#remove_role6_response = {'responses': [{'command': 'removeClientRole', 'error': 'Invalid/missing rolename'}]} + +# Client not found +remove_role7_command = { 'commands': [{'command': 'removeClientRole', 'username':'notfound', 'rolename':'notfound'}]} +remove_role7_response = {'responses': [{'command': 'removeClientRole', 'error': 'Client not found'}]} + +# Role not found +remove_role8_command = { 'commands': [{'command': 'removeClientRole', 'username':'admin', 'rolename':'notfound'}]} +remove_role8_response = {'responses': [{'command': 'removeClientRole', 'error': 'Role not found'}]} + + +# ========================================================================== +# Modify client +# ========================================================================== + +# Create a client to modify +modify_client0_command = { 'commands': [{'command': 'createClient', 'username':'user'}]} +modify_client0_response = {'responses': [{'command': 'createClient'}]} + +# No username +modify_client1_command = { 'commands': [{'command': 'modifyClient'}]} +modify_client1_response = {'responses': [{'command': 'modifyClient', 'error': 'Invalid/missing username'}]} + +# Username not a string +modify_client2_command = { 'commands': [{'command': 'modifyClient', 'username':5}]} +modify_client2_response = {'responses': [{'command': 'modifyClient', 'error': 'Invalid/missing username'}]} + +# Username not UTF-8 +#modify_client3_command = { 'commands': [{'command': 'modifyClient', 'username':5}]} +#modify_client3_response = {'responses': [{'command': 'modifyClient', 'error': 'Invalid/missing username'}]} + +# roles not a list +modify_client4_command = { 'commands': [{'command': 'modifyClient', 'username':'user', 'password':'test', 'roles':'string'}]} +modify_client4_response = {'responses': [{'command': 'modifyClient', 'error': "'roles' not an array"}]} + +# No rolename +modify_client5_command = { 'commands': [{'command': 'modifyClient', 'username':'user', 'roles':[{'rolename':5}]}]} +modify_client5_response = {'responses': [{'command': 'modifyClient', 'error': 'Invalid/missing rolename'}]} + +# rolename not a string +modify_client6_command = { 'commands': [{'command': 'modifyClient', 'username':'user', 'rolename':5}]} +modify_client6_response = {'responses': [{'command': 'modifyClient', 'error': 'Invalid/missing rolename'}]} + +# rolename not UTF-8 +#modify_client7_command = { 'commands': [{'command': 'modifyClient', 'username':'user'}]} +#modify_client7_response = {'responses': [{'command': 'modifyClient', 'error': 'Invalid/missing rolename'}]} + +# Client not found +modify_client8_command = { 'commands': [{'command': 'modifyClient', 'username':'notfound', 'rolename':'notfound'}]} +modify_client8_response = {'responses': [{'command': 'modifyClient', 'error': 'Client not found'}]} + +# Role not found +modify_client9_command = { 'commands': [{'command': 'modifyClient', 'username':'admin', 'rolename':'notfound'}]} +modify_client9_response = {'responses': [{'command': 'modifyClient', 'error': 'Role not found'}]} + + +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) + +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") + + command_check(sock, create_client1_command, create_client1_response, "1") + command_check(sock, create_client2_command, create_client2_response, "2") + #command_check(sock, create_client3_command, create_client3_response, "3") + command_check(sock, create_client4_command, create_client4_response, "4") + command_check(sock, create_client5_command, create_client5_response, "5") + command_check(sock, create_client6_command, create_client6_response, "6") + command_check(sock, create_client7_command, create_client7_response, "7") + command_check(sock, create_client8_command, create_client8_response, "8") + command_check(sock, create_client9_command, create_client9_response, "9") + command_check(sock, create_client10_command, create_client10_response, "10") + + command_check(sock, delete_client1_command, delete_client1_response, "1") + command_check(sock, delete_client2_command, delete_client2_response, "2") + #command_check(sock, delete_client3_command, delete_client3_response, "3") + command_check(sock, delete_client4_command, delete_client4_response, "4") + + command_check(sock, disable_client1_command, disable_client1_response, "1") + command_check(sock, disable_client2_command, disable_client2_response, "2") + #command_check(sock, disable_client3_command, disable_client3_response, "3") + command_check(sock, disable_client4_command, disable_client4_response, "4") + + command_check(sock, enable_client1_command, enable_client1_response, "1") + command_check(sock, enable_client2_command, enable_client2_response, "2") + #command_check(sock, enable_client3_command, enable_client3_response, "3") + command_check(sock, enable_client4_command, enable_client4_response, "4") + + command_check(sock, set_client_id1_command, set_client_id1_response, "1") + command_check(sock, set_client_id2_command, set_client_id2_response, "2") + #command_check(sock, set_client_id3_command, set_client_id3_response, "3") + command_check(sock, set_client_id4_command, set_client_id4_response, "4") + command_check(sock, set_client_id5_command, set_client_id5_response, "5") + #command_check(sock, set_client_id6_command, set_client_id6_response, "6") + command_check(sock, set_client_id7_command, set_client_id7_response, "7") + + command_check(sock, set_password1_command, set_password1_response, "1") + command_check(sock, set_password2_command, set_password2_response, "2") + #command_check(sock, set_password3_command, set_password3_response, "3") + command_check(sock, set_password4_command, set_password4_response, "4") + command_check(sock, set_password5_command, set_password5_response, "5") + command_check(sock, set_password6_command, set_password6_response, "6") + command_check(sock, set_password7_command, set_password7_response, "7") + + command_check(sock, get_client1_command, get_client1_response, "1") + command_check(sock, get_client2_command, get_client2_response, "2") + #command_check(sock, get_client3_command, get_client3_response, "3") + command_check(sock, get_client4_command, get_client4_response, "4") + + command_check(sock, add_role1_command, add_role1_response, "1") + command_check(sock, add_role2_command, add_role2_response, "2") + #command_check(sock, add_role3_command, add_role3_response, "3") + command_check(sock, add_role4_command, add_role4_response, "4") + command_check(sock, add_role5_command, add_role5_response, "5") + #command_check(sock, add_role6_command, add_role6_response, "6") + command_check(sock, add_role7_command, add_role7_response, "7") + command_check(sock, add_role8_command, add_role8_response, "8") + + command_check(sock, remove_role1_command, remove_role1_response, "1") + command_check(sock, remove_role2_command, remove_role2_response, "2") + #command_check(sock, remove_role3_command, remove_role3_response, "3") + command_check(sock, remove_role4_command, remove_role4_response, "4") + command_check(sock, remove_role5_command, remove_role5_response, "5") + #command_check(sock, remove_role6_command, remove_role6_response, "6") + command_check(sock, remove_role7_command, remove_role7_response, "7") + command_check(sock, remove_role8_command, remove_role8_response, "8") + + command_check(sock, modify_client0_command, modify_client0_response, "1") + command_check(sock, modify_client1_command, modify_client1_response, "1") + command_check(sock, modify_client2_command, modify_client2_response, "2") + #command_check(sock, modify_client3_command, modify_client3_response, "3") + command_check(sock, modify_client4_command, modify_client4_response, "4") + #command_check(sock, modify_client5_command, modify_client5_response, "5") + #command_check(sock, modify_client6_command, modify_client6_response, "6") + #command_check(sock, modify_client7_command, modify_client7_response, "7") + #command_check(sock, modify_client8_command, modify_client8_response, "8") + + + 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 c501783e..761a031e 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -227,6 +227,7 @@ ifeq ($(WITH_CJSON),yes) ./14-dynsec-anon-group.py ./14-dynsec-auth.py ./14-dynsec-client.py + ./14-dynsec-client-invalid.py ./14-dynsec-default-access.py ./14-dynsec-disable-client.py ./14-dynsec-group.py diff --git a/test/broker/test.py b/test/broker/test.py index 95cae79a..cf117e71 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -193,6 +193,7 @@ tests = [ (1, './14-dynsec-anon-group.py'), (1, './14-dynsec-auth.py'), (1, './14-dynsec-client.py'), + (1, './14-dynsec-client-invalid.py'), (1, './14-dynsec-default-access.py'), (1, './14-dynsec-disable-client.py'), (1, './14-dynsec-group.py'),