Commit 0da895c7 authored by Jelte Jansen's avatar Jelte Jansen
Browse files

[2713] Add -u/--user and -p/--password arguments

But essentially, this is a full rewrite of the tool, since to handle it nicely I had to get rid of most of the functions and make a somewhat nicer class of it.

Also added a -q option while i was at it
parent cd98bdae
......@@ -23,11 +23,8 @@ import random
from hashlib import sha1
import csv
import getpass
#remove
import getopt
from optparse import OptionParser, OptionValueError
import os
import sys; sys.path.append ('@@PYTHONPATH@@')
import isc.util.process
......@@ -36,78 +33,128 @@ isc.util.process.rename()
VERSION_STRING = 'b10-cmdctl-usermgr @PACKAGE_VERSION@'
DEFAULT_FILE = 'cmdctl-accounts.csv'
def gen_password_hash(password):
salt = "".join(chr(random.randint(33, 127)) for x in range(64))
saltedpwd = sha1((password + salt).encode()).hexdigest()
return salt, saltedpwd
def username_exist(name, filename):
# The file may doesn't exist.
exist = False
csvfile = None
try:
csvfile = open(filename)
reader = csv.reader(csvfile)
for row in reader:
if name == row[0]:
exist = True
break
except Exception:
pass
if csvfile:
class UserManager:
def __init__(self, options):
self.options = options
def print(self, msg):
if not self.options.quiet:
print(msg)
def gen_password_hash(self, password):
salt = "".join(chr(random.randint(33, 127)) for x in range(64))
saltedpwd = sha1((password + salt).encode()).hexdigest()
return salt, saltedpwd
def username_exists(self, name):
if not os.path.exists(self.options.output_file):
return False
exist = False
csvfile = None
with open(self.options.output_file) as csvfile:
reader = csv.reader(csvfile)
for row in reader:
if name == row[0]:
exist = True
break
return exist
def save_userinfo(self, username, pw, salt, filename):
csvfile = open(filename, 'a')
writer = csv.writer(csvfile)
writer.writerow([username, pw, salt])
csvfile.close()
return exist
def save_userinfo(username, pw, salt, filename):
csvfile = open(filename, 'a')
writer = csv.writer(csvfile)
writer.writerow([username, pw, salt])
csvfile.close()
print("\n create new account successfully! \n")
def set_options(parser):
parser.add_option("-f", "--file",
dest="output_file", default=DEFAULT_FILE,
help="Specify the file to append user name and password"
)
def main():
parser = OptionParser(version = VERSION_STRING)
set_options(parser)
(options, _) = parser.parse_args()
filename = options.output_file
try:
self.print("User added\n")
def add_user(self, name, password):
"""
Add the given username/password combination to the file.
First checks if the username exists, and returns False if so.
If not, it is added, and this method returns True.
"""
if self.username_exists(name):
return False
salt, pw = self.gen_password_hash(password)
self.save_userinfo(name, pw, salt, self.options.output_file)
return True
def interactive_mode(self):
while True :
name = input("Desired Login Name:")
name = input("Username to add: ")
if name == '':
print("error, user name can't be empty")
print("error, username can't be empty")
continue
if username_exist(name, filename):
print("user name already exists!")
if self.username_exists(name):
print("user already exists!")
continue
while True:
pwd1 = getpass.getpass("Choose a password:")
pwd2 = getpass.getpass("Re-enter password:")
pwd1 = getpass.getpass("Choose a password: ")
pwd2 = getpass.getpass("Re-enter password: ")
if pwd1 != pwd2:
print("password is not same, please input again")
print("passwords do not match, try again")
else:
break;
salt, pw = gen_password_hash(pwd1)
save_userinfo(name, pw, salt, filename)
inputdata = input('continue to create new account by input \'y\' or \'Y\':')
if not self.add_user(name, pwd1):
self.print("Error: username exists")
inputdata = input('Add another user (y/n)? ')
if inputdata not in ['y', 'Y']:
break
except KeyboardInterrupt:
pass
def run(self):
self.print("Using accounts file: " + self.options.output_file)
filename = self.options.output_file
if self.options.username is not None or\
self.options.password is not None:
if self.options.username is None:
self.print("Error: password but no username given")
return 1
if self.options.password is None:
self.print("Error: username but no password given")
return 1
if not self.add_user(self.options.username,
self.options.password):
self.print("Error: username exists")
else:
try:
self.interactive_mode()
except KeyboardInterrupt:
pass
return 0
def set_options(parser):
parser.add_option("-f", "--file",
dest="output_file", default=DEFAULT_FILE,
help="Specify the file to append user name and password"
)
parser.add_option("-u", "--username",
dest="username", default=None,
help="Specify username to add"
)
parser.add_option("-p", "--password",
dest="password", default=None,
help="Specify password to add"
)
parser.add_option("-q", "--quiet",
dest="quiet", action="store_true", default=False,
help="Quiet mode, don't print any output"
)
def main():
parser = OptionParser(version = VERSION_STRING)
set_options(parser)
(options, _) = parser.parse_args()
usermgr = UserManager(options)
return usermgr.run()
if __name__ == '__main__':
main()
result = main()
sys.exit(result)
......@@ -13,10 +13,12 @@
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import csv
from hashlib import sha1
import imp
import os
import unittest
import subprocess
import imp
import unittest
def run(command):
"""
......@@ -44,9 +46,28 @@ class TestUserMgr(unittest.TestCase):
def check_output_file(self, expected_content):
self.assertTrue(os.path.exists(self.OUTPUT_FILE))
with open(self.OUTPUT_FILE, 'r') as f:
content = f.readlines()
self.assertEqual(expected_content, content)
csv_entries = []
with open(self.OUTPUT_FILE) as csvfile:
reader = csv.reader(csvfile)
for row in reader:
csv_entries.append(row)
self.assertEqual(len(expected_content), len(csv_entries))
csv_entries.reverse()
for expected_entry in expected_content:
expected_name = expected_entry[0]
expected_pass = expected_entry[1]
csv_entry = csv_entries.pop()
entry_name = csv_entry[0]
entry_salt = csv_entry[2]
entry_hash = csv_entry[1]
self.assertEqual(expected_name, entry_name)
expected_hash =\
sha1((expected_pass + entry_salt).encode()).hexdigest()
self.assertEqual(expected_hash, entry_hash)
def run_check(self, expected_returncode, expected_stdout, expected_stderr, command):
"""
......@@ -59,11 +80,11 @@ class TestUserMgr(unittest.TestCase):
May be None, in which case the check is skipped.
"""
(returncode, stdout, stderr) = run(command)
self.assertEqual(expected_returncode, returncode, " ".join(command))
if expected_stdout is not None:
self.assertEqual(expected_stdout, stdout.decode())
if expected_stderr is not None:
self.assertEqual(expected_stderr, stderr.decode())
if expected_stdout is not None:
self.assertEqual(expected_stdout, stdout.decode())
self.assertEqual(expected_returncode, returncode, " ".join(command))
def test_help(self):
self.run_check(0,
......@@ -74,10 +95,58 @@ Options:
-h, --help show this help message and exit
-f OUTPUT_FILE, --file=OUTPUT_FILE
Specify the file to append user name and password
-u USERNAME, --username=USERNAME
Specify username to add
-p PASSWORD, --password=PASSWORD
Specify password to add
-q, --quiet Quiet mode, don't print any output
''',
'',
[self.TOOL, '-h'])
def test_create_users(self):
"""
Test that a file is created, and users are added.
Also tests quiet mode for adding a user to an existing file.
"""
# content is a list of (user, pass) tuples
expected_content = []
# Creating a file
self.run_check(0,
'Using accounts file: test_users.csv\n'
'User added\n\n',
'',
[ self.TOOL,
'-f', self.OUTPUT_FILE,
'-u', 'user1',
'-p', 'pass1' ])
expected_content.append(('user1', 'pass1'))
self.check_output_file(expected_content)
# Add to existing file
self.run_check(0,
'Using accounts file: test_users.csv\n'
'User added\n\n',
'',
[ self.TOOL,
'-f', self.OUTPUT_FILE,
'-u', 'user2',
'-p', 'pass2' ])
expected_content.append(('user2', 'pass2'))
self.check_output_file(expected_content)
# Quiet mode
self.run_check(0,
'',
'',
[ self.TOOL, '-q',
'-f', self.OUTPUT_FILE,
'-u', 'user3',
'-p', 'pass3' ])
expected_content.append(('user3', 'pass3'))
self.check_output_file(expected_content)
def test_default_file(self):
"""
Check the default file is the correct one.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment