[Zope-Checkins] CVS: Zope/utilities - zpasswd.py:1.4

Chris McDonough chrism@zope.com
Tue, 22 Jul 2003 16:48:43 -0400


Update of /cvs-repository/Zope/utilities
In directory cvs.zope.org:/tmp/cvs-serv15504

Added Files:
	zpasswd.py 
Log Message:
Move zpasswd into utilities.


=== Zope/utilities/zpasswd.py 1.3 => 1.4 ===
--- /dev/null	Tue Jul 22 16:48:43 2003
+++ Zope/utilities/zpasswd.py	Tue Jul 22 16:48:38 2003
@@ -0,0 +1,213 @@
+#!/usr/bin/env python
+##############################################################################
+#
+# Copyright (c) 2001,2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""Zope user bootstrap system
+
+Usage: %(PROGRAM)s [options] filename
+
+If this program is called without command-line options, it will prompt
+for all necessary information.  The available options are:
+
+    -u / --username=
+    Set the username to be used for the initial user or the emergency user
+
+    -p / --password=
+    Set the password
+
+    -e / --encoding=
+    Set the encryption/encoding rules.  Defaults to SHA-1. OPTIONAL
+
+    -d / --domains=
+    Set the domain names that the user user can log in from.  Defaults to
+    any. OPTIONAL.
+
+    -h / --help
+    Print this help text and exit.
+
+    Filename is required and should be the name of the file to store the
+    information in (usually "inituser" or "access").
+"""
+
+__version__='$Revision$ '[11:-2]
+
+import sys,  sha, binascii, random, getopt, getpass, os
+
+try:
+    from crypt import crypt
+except ImportError:
+    crypt = None
+
+PROGRAM = sys.argv[0]
+COMMASPACE = ', '
+
+
+def generate_salt():
+    """Generate a salt value for the crypt function."""
+    salt_choices = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                    "abcdefghijklmnopqrstuvwxyz"
+                    "0123456789./")
+    return random.choice(salt_choices)+random.choice(salt_choices)
+
+def generate_passwd(password, encoding):
+    encoding=encoding.upper()
+    if encoding == 'SHA':
+        pw = '{SHA}' + binascii.b2a_base64(sha.new(password).digest())[:-1]
+    elif encoding == 'CRYPT':
+        pw = '{CRYPT}' + crypt(password, generate_salt())
+    elif encoding == 'CLEARTEXT':
+        pw = password
+
+    return pw
+
+def write_generated_password(home, ac_path, username):
+    pw_choices = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                  "abcdefghijklmnopqrstuvwxyz"
+                  "0123456789!")
+    acfile=open(ac_path, 'w')
+    pw = ''
+    for i in range(8):
+        pw = pw + random.choice(pw_choices)
+    acfile.write('%s:%s\n' % (username, generate_passwd(pw, 'SHA')))
+    acfile.close()
+    os.chmod(ac_path, 0644)
+    return pw
+
+def write_access(home, user='', group=''):
+    ac_path=os.path.join(home, 'access')
+    if not os.path.exists(ac_path):
+        print '-'*78
+        print 'creating default access file'
+        pw = write_generated_password(home, ac_path, 'emergency')
+        print """Note:
+        The emergency user name and password are 'emergency'
+        and '%s'.
+
+        You can change the emergency name and password with the
+        zpasswd script.  To find out more, type:
+
+        %s zpasswd.py
+        """ % (pw, sys.executable)
+
+        import do; do.ch(ac_path, user, group)
+
+def write_inituser(home, user='', group=''):
+    ac_path=os.path.join(home, 'inituser')
+    if not os.path.exists(ac_path):
+        print '-'*78
+        print 'creating default inituser file'
+        pw = write_generated_password(home, ac_path, 'admin')
+        print """Note:
+        The initial user name and password are 'admin'
+        and '%s'.
+
+        You can change the name and password through the web
+        interface or using the 'zpasswd.py' script.
+        """ % pw
+
+        import do; do.ch(ac_path, user, group)
+
+
+def usage(code, msg=''):
+    print >> sys.stderr, __doc__ % globals()
+    if msg:
+        print >> sys.stderr, msg
+    sys.exit(code)
+
+
+def main():
+    shortopts = 'u:p:e:d:h'
+    longopts = ['username=',
+                'password=',
+                'encoding=',
+                'domains=',
+                'help']
+
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], shortopts, longopts)
+    except getopt.error, msg:
+        usage(1, msg)
+
+    # Defaults
+    username = password = None
+    domains = ''
+    encoding = 'SHA'
+
+    for opt, arg in opts:
+        if opt in ('-h', '--help'):
+            usage(0)
+        elif opt in ('-u', '--username'):
+            username = arg
+        elif opt in ('-p', '--password'):
+            password = arg
+        elif opt in ('-e', '--encoding'):
+            encoding = arg
+        elif opt in ('-d', '--domains'):
+            domains = ':' + arg
+
+    # Extra command line arguments?
+    if len(args) == 0:
+        usage(1, 'filename is required')
+    elif len(args) == 1:
+        access_file = open(args[0], 'w')
+    else:
+        usage(1, 'Extra command line arguments: ' + COMMASPACE.join(args))
+
+    if opts:
+        # There were some command line args, so verify
+        if username is None or password is None:
+            usage(1, '-u and -p are required')
+    else:
+        # No command line args, so prompt
+        while 1:
+            username = raw_input("Username: ")
+            if username != '':
+                break
+
+        while 1:
+            password = getpass.getpass("Password: ")
+            verify = getpass.getpass("Verify password: ")
+            if verify == password:
+                break
+            else:
+                password = verify = ''
+                print "Password mismatch, please try again..."
+
+        while 1:
+            print """
+Please choose a format from:
+
+SHA - SHA-1 hashed password (default)
+CRYPT - UNIX-style crypt password
+CLEARTEXT - no protection
+"""
+            encoding = raw_input("Encoding: ")
+            if encoding == '':
+                encoding = 'SHA'
+                break
+            if encoding.upper() in ['SHA', 'CRYPT', 'CLEARTEXT']:
+                break
+
+        domains = raw_input("Domain restrictions: ")
+        if domains:
+            domains = ":" + domains
+
+    # Done with prompts and args
+    access_file.write(username + ":" +
+                      generate_passwd(password, encoding) +
+                      domains)
+
+
+# If called from the command line
+if __name__=='__main__':
+    main()