-
Notifications
You must be signed in to change notification settings - Fork 592
/
tabpy_user.py
executable file
·134 lines (105 loc) · 4.29 KB
/
tabpy_user.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
"""
Utility for managing user names and passwords for TabPy.
For more information about how to configure and use authentication for
TabPy read the documentation at https://github.com/tableau/TabPy.
Usage:
tabpy-user add (-u NAME | --user <NAME>) [-p PWD | --password PWD] (-f FILE | --pwdfile FILE)
tabpy-user update (-u NAME | --user <NAME>) [-p PWD | --password PWD] (-f FILE | --pwdfile FILE)
tabpy-user -h | --help
Options:
-h --help Show this screen.
-u NAME --username NAME Username to add to password file.
-p PWD --password PWD Password for the username. If not specified a
password will be generated.
-f FILE --pwdfile FILE Fully qualified path to passwords file.
"""
import docopt
import logging
import secrets
from tabpy.tabpy_server.app.util import parse_pwd_file
from tabpy.tabpy_server.handlers.util import hash_password
logger = logging.getLogger(__name__)
def generate_password(pwd_len=16):
# List of characters to generate password from.
# We want to avoid to use similarly looking pairs like
# (O, 0), (1, l), etc.
lower_case_letters = "abcdefghijkmnpqrstuvwxyz"
upper_case_letters = "ABCDEFGHIJKLMPQRSTUVWXYZ"
digits = "23456789"
# and for punctuation we want to exclude some characters
# like inverted comma which can be hard to find and/or
# type
# change this string if you are supporting an
# international keyboard with differing keys available
punctuation = "!#$%&()*+,-./:;<=>?@[\\]^_{|}~"
# we also want to try to have more letters and digits in
# generated password than punctuation marks
password_chars = (
lower_case_letters
+ lower_case_letters
+ upper_case_letters
+ upper_case_letters
+ digits
+ digits
+ punctuation
)
pwd = "".join(secrets.choice(password_chars) for i in range(pwd_len))
logger.info(f'Generated password: "{pwd}"')
return pwd
def store_passwords_file(pwdfile, credentials):
with open(pwdfile, "wt") as f:
for username, pwd in credentials.items():
f.write(f"{username} {pwd}\n")
return True
def add_user(args, credentials):
username = args["--username"].lower()
logger.info(f'Adding username "{username}"')
if username in credentials:
logger.error(
f"Can't add username {username} as it is already present"
" in passwords file. Do you want to run the "
'"update" command instead?'
)
return False
password = args["--password"]
logger.info(f'Adding username "{username}" with password "{password}"...')
credentials[username] = hash_password(username, password)
if store_passwords_file(args["--pwdfile"], credentials):
logger.info(f'Added username "{username}" with password "{password}"')
else:
logger.info(
f'Could not add username "{username}" , ' f'password "{password}" to file'
)
def update_user(args, credentials):
username = args["--username"].lower()
logger.info(f'Updating username "{username}"')
if username not in credentials:
logger.error(
f'Username "{username}" not found in passwords file. '
'Do you want to run "add" command instead?'
)
return False
password = args["--password"]
logger.info(f'Updating username "{username}" password to "{password}"')
credentials[username] = hash_password(username, password)
return store_passwords_file(args["--pwdfile"], credentials)
def process_command(args, credentials):
if args["add"]:
return add_user(args, credentials)
elif args["update"]:
return update_user(args, credentials)
else:
logger.error(f'Unknown command "{args.command}"')
return False
def main():
logging.basicConfig(level=logging.DEBUG, format="%(message)s")
args = docopt.docopt(__doc__)
succeeded, credentials = parse_pwd_file(args["--pwdfile"])
if not succeeded and not args["add"]:
return
if args["--password"] is None:
args["--password"] = generate_password()
process_command(args, credentials)
return
if __name__ == "__main__":
main()