1
##############################################################################
3
# Copyright (c) 2004 Zope Foundation and Contributors.
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
13
##############################################################################
14
"""Implementation of the zpasswd script.
16
$Id: zpasswd.py 112149 2010-05-07 15:40:42Z ulif $
22
from xml.sax.saxutils import quoteattr
24
VERSION = pkg_resources.get_distribution('zope.password').version
27
"""Top-level script function to create a new principals."""
31
options = parse_args(argv)
37
app = Application(options)
40
except KeyboardInterrupt:
45
class Principal(object):
48
>>> principal = Principal("id", "title", "login", "password")
57
>>> principal = Principal("id", "title", "login", "password",
58
... "description", "SHA1")
65
description="description"
66
password_manager="SHA1"
70
def __init__(self, id, title, login, password,
71
description="", password_manager_name="Plain Text"):
74
self.password = password
76
self.description = description
77
self.password_manager_name = password_manager_name
82
' id=%s' % quoteattr(self.id),
83
' title=%s' % quoteattr(self.title),
84
' login=%s' % quoteattr(self.login),
85
' password=%s' % quoteattr(self.password)
88
lines.append(' description=%s' % quoteattr(self.description))
89
if self.password_manager_name != "Plain Text":
90
lines.append(' password_manager=%s'
91
% quoteattr(self.password_manager_name))
96
return "\n".join(self.getLines())
99
============================================
100
Principal information for inclusion in ZCML:
104
Please choose an id for the principal.
108
Please choose a title for the principal.
112
Please choose a login for the principal.
116
Please provide a password for the principal.
119
DESCRIPTION_TITLE = """
120
Please provide an optional description for the principal.
123
class Application(object):
127
title_title = TITLE_TITLE
128
login_title = LOGIN_TITLE
129
password_title = PASSWORD_TITLE
130
description_title = DESCRIPTION_TITLE
132
def __init__(self, options):
133
self.options = options
134
self.need_blank_line = False
136
def read_input_line(self, prompt):
137
# The tests replace this to make sure the right things happen.
138
return raw_input(prompt)
140
def read_password(self, prompt):
141
# The tests replace this to make sure the right things happen.
144
return getpass.getpass(prompt)
145
except KeyboardInterrupt:
146
# The cursor was left on the same line as the prompt,
147
# which we don't like. Print a blank line.
152
options = self.options
154
if not options.destination:
155
destination = sys.stdout
157
destination = open(options.destination, "wb")
159
principal = self.get_principal()
161
if destination is sys.stdout:
163
print >>destination, principal
168
def get_principal(self):
169
id = self.get_value(self.id_title, "Id: ", "Id may not be empty")
170
title = self.get_value(self.title_title, "Title: ",
171
"Title may not be empty")
172
login = self.get_value(self.login_title, "Login: ",
173
"Login may not be empty")
174
password_manager_name, password_manager = self.get_password_manager()
175
password = self.get_password()
176
description = self.get_value(self.description_title, "Description: ",)
178
password = password_manager.encodePassword(password)
179
return Principal(id, title, login, password, description,
180
password_manager_name)
182
def get_value(self, title, prompt, error=""):
183
self.print_message(title)
184
self.need_blank_line = True
186
value = self.read_input_line(prompt).strip()
187
if not value and error:
188
print >>sys.stderr, error
192
def get_password_manager(self):
194
self.print_message("Password manager:")
196
managers = self.options.managers
198
for i, (name, manager) in enumerate(managers):
199
print "% i. %s" % (i + 1, name)
203
self.need_blank_line = True
205
password_manager = self.read_input_line(
206
"Password Manager Number [%s]: " % (default + 1))
207
if not password_manager:
210
elif password_manager.isdigit():
211
index = int(password_manager)
212
if index > 0 and index <= len(managers):
215
print >>sys.stderr, "You must select a password manager"
216
print "%s password manager selected" % managers[index][0]
217
return managers[index]
219
def get_password(self):
220
self.print_message(self.password_title)
222
password = self.read_password("Password: ")
224
print >>sys.stderr, "Password may not be empty"
226
if password != password.strip() or password.split() != [password]:
227
print >>sys.stderr, "Password may not contain spaces"
230
again = self.read_password("Verify password: ")
231
if again != password:
232
print >>sys.stderr, "Password not verified!"
236
def print_message(self, message):
237
if self.need_blank_line:
239
self.need_blank_line = False
242
def get_password_managers(config_path=None):
244
from zope.password.password import managers
246
from zope.configuration import xmlconfig
247
from zope.component import getUtilitiesFor
248
from zope.password.interfaces import IPasswordManager
250
print "Loading configuration..."
251
config = xmlconfig.file(config_path)
253
for name, manager in getUtilitiesFor(IPasswordManager):
254
if name == "Plain Text":
255
managers.insert(0, (name, manager))
257
managers.append((name, manager))
259
from zope.password.password import managers
262
def parse_args(argv):
263
"""Parse the command line, returning an object representing the input."""
264
path, prog = os.path.split(os.path.realpath(argv[0]))
265
p = optparse.OptionParser(prog=prog,
266
usage="%prog [options]",
268
p.add_option("-c", "--config", dest="config", metavar="FILE",
269
help=("path to the site.zcml configuration file"
270
" (more accurate but slow password managers registry creation)"))
271
p.add_option("-o", "--output", dest="destination", metavar="FILE",
272
help=("the file in which the output will be saved"
273
" (STDOUT by default)"))
274
options, args = p.parse_args(argv[1:])
275
options.managers = get_password_managers(options.config)
276
options.program = prog
277
options.version = VERSION
279
p.error("too many arguments")