Initial commit of users role

Change-Id: I808c990019b059e0a412986d9b4c010689255581
diff --git a/goodpassword.py b/goodpassword.py
new file mode 100755
index 0000000..29719dd
--- /dev/null
+++ b/goodpassword.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+#
+# SPDX-FileCopyrightText: © 2020 Open Networking Foundation <support@opennetworking.org>
+# SPDX-License-Identifier: Apache-2.0
+
+# goodpassword.py
+
+import getpass
+import sys
+import zxcvbn
+from passlib.hash import bcrypt, sha512_crypt
+
+MIN_LEN = 12
+REQ_SCORE = 4
+
+print("goodpassword.py - generates unix password hashes of high quality")
+pw = getpass.getpass()
+
+# reject short passwords
+pwlen = len(pw)
+if pwlen < MIN_LEN:
+    print(
+        "Passwords must be at least %d characters long (the one supplied was %d)."
+        % (MIN_LEN, pwlen)
+    )
+    sys.exit(1)
+
+# generate password score
+zxscore = zxcvbn.zxcvbn(pw)
+
+# Print any suggestions
+if zxscore["feedback"]["warning"]:
+    print("Warning: %s" % zxscore["feedback"]["warning"])
+
+if zxscore["feedback"]["suggestions"]:
+    print("Suggestions:")
+    for suggestion in zxscore["feedback"]["suggestions"]:
+        print(" - %s" % suggestion)
+
+print(
+    "This password had a complexity score of %d (must score at least %d)"
+    % (zxscore["score"], REQ_SCORE)
+)
+
+print(
+    "Time to crack: %s"
+    % zxscore["crack_times_display"]["offline_slow_hashing_1e4_per_second"]
+)
+
+years = 5
+min_crack_seconds = 60 * 60 * 24 * 365 * years  # number of seconds per year
+# if the password crack time is too short
+if (
+    zxscore["crack_times_seconds"]["offline_slow_hashing_1e4_per_second"]
+    < min_crack_seconds
+):
+    print(
+        "This password was crackable in less than %d years, please make it longer/more complex"
+        % years
+    )
+    sys.exit(1)
+
+# if the password score is too low
+if zxscore["score"] < REQ_SCORE:
+    sys.exit(1)
+
+# password is high enough quality
+# this make take a short while so let the user know
+print("Generating password hashes...")
+print('bcrypt: "%s"' % bcrypt.using(rounds=16).hash(pw))
+print('sha512crypt: "%s"' % sha512_crypt.hash(pw))