Add mosquitto_passwd tests

pull/2345/merge
Roger A. Light 3 years ago
parent 9cc5d1d6ff
commit b49631df23

@ -109,10 +109,7 @@ static FILE *mpw_tmpfile(void)
int log__printf(void *mosq, unsigned int level, const char *fmt, ...)
{
/* Stub for misc_mosq.c */
UNUSED(mosq);
UNUSED(level);
UNUSED(fmt);
return 0;
UNUSED(mosq); UNUSED(level); UNUSED(fmt); return 0;
}
@ -145,35 +142,30 @@ static int output_new_password(FILE *fptr, const char *username, const char *pas
pw.hashtype = hashtype;
if(pw__hash(password, &pw, true, iterations)){
fprintf(stderr, "Error: Unable to hash password.\n");
return 1;
}
rc = base64__encode(pw.salt, pw.salt_len, &salt64);
rc = pw__hash(password, &pw, true, iterations);
if(rc){
free(salt64);
fprintf(stderr, "Error: Unable to encode salt.\n");
return 1;
}
rc = base64__encode(pw.password_hash, sizeof(pw.password_hash), &hash64);
if(rc){
free(salt64);
free(hash64);
fprintf(stderr, "Error: Unable to encode hash.\n");
return 1;
}
if(pw.hashtype == pw_sha512_pbkdf2){
fprintf(fptr, "%s:$%d$%d$%s$%s\n", username, hashtype, iterations, salt64, hash64);
fprintf(stderr, "Error: Unable to hash password.\n");
}else{
fprintf(fptr, "%s:$%d$%s$%s\n", username, hashtype, salt64, hash64);
rc = base64__encode(pw.salt, pw.salt_len, &salt64);
if(rc){
fprintf(stderr, "Error: Unable to encode salt.\n");
}else{
rc = base64__encode(pw.password_hash, sizeof(pw.password_hash), &hash64);
if(rc){
fprintf(stderr, "Error: Unable to encode hash.\n");
}else{
if(pw.hashtype == pw_sha512_pbkdf2){
fprintf(fptr, "%s:$%d$%d$%s$%s\n", username, hashtype, iterations, salt64, hash64);
}else{
fprintf(fptr, "%s:$%d$%s$%s\n", username, hashtype, salt64, hash64);
}
}
}
}
free(salt64);
free(hash64);
return 0;
return rc;
}

@ -0,0 +1,41 @@
#!/usr/bin/env python3
# Test parsing of command line args and errors. Does not test arg functionality.
from mosq_test_helper import *
def do_test(args, rc_expected, response=None, input=None):
proc = subprocess.run([mosq_test.get_build_root()+"/apps/mosquitto_passwd/mosquitto_passwd"]
+ args,
capture_output=True, encoding='utf-8', timeout=2, input=input)
if response is not None:
if proc.stderr != response:
print(len(proc.stderr))
print(len(response))
raise ValueError(proc.stderr)
if proc.returncode != rc_expected:
print(proc.returncode)
raise ValueError(args)
do_test([], 1) # For the usage message
do_test(["-H"], 1, response="Error: -H argument given but not enough other arguments.\n")
do_test(["-H", "nohash"], 1, response="Error: Unknown hash type 'nohash'\n")
do_test(["-I"], 1, response="Error: -I argument given but not enough other arguments.\n")
do_test(["-I", "0"], 1, response="Error: Number of iterations must be > 0.\n")
do_test(["-c", "-D"], 1, response="Error: -c and -D cannot be used together.\n")
do_test(["-c", "-U"], 1, response="Error: -c and -U cannot be used together.\n")
do_test(["-U", "-D"], 1, response="Error: -D and -U cannot be used together.\n")
do_test(["-b", "-D"], 1, response="Error: -b and -D cannot be used together.\n")
do_test(["-c", "-b"], 1, response="Error: -c argument given but password file, username, or password missing.\n")
do_test(["-c"], 1, response="Error: -c argument given but password file or username missing.\n")
do_test(["-D"], 1, response="Error: -D argument given but password file or username missing.\n")
do_test(["-U"], 1, response="Error: -U argument given but password file missing.\n")
do_test(["-D", "pwfile", "bad-username:"], 1, response="Error: Username must not contain the ':' character.\n")
do_test(["-D", "pwfile", "bad-username\n"], 1, response="Error: Username must not contain control characters.\n")
do_test(["-D", "pwfile", "a"*65536], 1, response="Error: Username must be less than 65536 characters long.\n")
do_test(["-c", "file", "username"], 2, response="Error: Passwords do not match.\n", input="not\nmatching\n")
exit(0)

@ -0,0 +1,103 @@
#!/usr/bin/env python3
from mosq_test_helper import *
import json
import shutil
import signal
def write_config(filename, pw_file, port):
with open(filename, 'w') as f:
f.write(f"listener {port}\n")
f.write("allow_anonymous false\n")
f.write(f"password_file {pw_file}\n")
def client_check(port, username, password, rc):
connect_packet = mosq_test.gen_connect("pwd-test", username=username, password=password)
connack_packet = mosq_test.gen_connack(rc=rc)
sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port)
sock.close()
def passwd_cmd(args, port, response=None, input=None):
proc = subprocess.run([mosq_test.get_build_root()+"/apps/mosquitto_passwd/mosquitto_passwd"]
+ args,
capture_output=True, encoding='utf-8', timeout=2, input=input)
if response is not None:
if proc.stdout != response:
print(len(proc.stdout))
print(len(response))
raise ValueError(proc.stdout)
if proc.returncode != 0:
raise ValueError(args)
port = mosq_test.get_port()
conf_file = os.path.basename(__file__).replace('.py', '.conf')
pw_file = os.path.basename(__file__).replace('.py', '.pwfile')
write_config(conf_file, pw_file, port)
# Generate initial password file
passwd_cmd(["-H", "sha512", "-c", "-b", pw_file, "user1", "pass1"], port)
passwd_cmd(["-H", "sha512-pbkdf2", pw_file, "user2"], port, input="cmd\ncmd\n")
# Then start broker
broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port, nolog=True)
try:
rc = 1
client_check(port, "user1", "badpass", 5)
client_check(port, "user1", "pass1", 0)
client_check(port, "user2", "badpass", 5)
client_check(port, "user2", "cmd", 0)
client_check(port, "user3", "badpass", 5)
client_check(port, "user3", "goodpass", 5)
# Update password
passwd_cmd(["-H", "sha512-pbkdf2", "-b", pw_file, "user1", "newpass"], port)
broker.send_signal(signal.SIGHUP)
client_check(port, "user1", "badpass", 5)
client_check(port, "user1", "newpass", 0)
client_check(port, "user2", "badpass", 5)
client_check(port, "user2", "cmd", 0)
client_check(port, "user3", "badpass", 5)
client_check(port, "user3", "goodpass", 5)
# New user
passwd_cmd(["-b", pw_file, "user3", "goodpass"], port)
broker.send_signal(signal.SIGHUP)
client_check(port, "user1", "badpass", 5)
client_check(port, "user1", "newpass", 0)
client_check(port, "user2", "badpass", 5)
client_check(port, "user2", "cmd", 0)
client_check(port, "user3", "badpass", 5)
client_check(port, "user3", "goodpass", 0)
# Delete user
passwd_cmd(["-D", pw_file, "user2"], port)
broker.send_signal(signal.SIGHUP)
client_check(port, "user1", "badpass", 5)
client_check(port, "user1", "newpass", 0)
client_check(port, "user2", "badpass", 5)
client_check(port, "user2", "cmd", 5)
client_check(port, "user3", "badpass", 5)
client_check(port, "user3", "goodpass", 0)
rc = 0
except mosq_test.TestError:
pass
except Exception as err:
print(err)
finally:
os.remove(conf_file)
os.remove(pw_file)
broker.terminate()
if mosq_test.wait_for_subprocess(broker):
print("broker not terminated")
if rc == 0: rc=1
exit(rc)

@ -8,7 +8,7 @@ all :
check : test
ptest : test
test : 01 02
test : 01 02 03
01 :
./01-db-dump-client-stats.py
@ -24,4 +24,8 @@ test : 01 02
./02-ctrl-broker.py
./02-ctrl-dynsec.py
03 :
./03-passwd-args.py
./03-passwd-changes.py
clean:

Loading…
Cancel
Save