Commit 08dbcb7f authored by Shane Hathaway's avatar Shane Hathaway

Merged UserBootstrappingBranch and added documentation to CHANGES, FAQ,

and SECURITY.
parent cf9fdb30
...@@ -33,7 +33,16 @@ Zope changes ...@@ -33,7 +33,16 @@ Zope changes
- Improved Ownership controls. Now you simply choose whether - Improved Ownership controls. Now you simply choose whether
or not to take ownership of sub-objects when taking or not to take ownership of sub-objects when taking
ownership. There is no need to control implicit/explicit ownership. There is no need to control implicit/explicit
ownership. ownership.
- Changed the Zope installation procedure so it is only
necessary to create one user account and that user is
stored in the ZODB.
- Implemented the "emergency user" concept, which is the new
name for what was called the superuser.
Bugs Fixed Bugs Fixed
...@@ -58,3 +67,10 @@ Zope changes ...@@ -58,3 +67,10 @@ Zope changes
- Undid a bug fix that caused the DateTime unit tests to fail. - Undid a bug fix that caused the DateTime unit tests to fail.
- Removed the requirement that an "access" file exist.
"access" is now only needed to create an emergency user
account.
- Disabled the monitor port by default because, initially,
there is no emergency user, and thus no password that
can be used to protect the port.
...@@ -110,6 +110,28 @@ Zope Installation Frequently Asked Questions ...@@ -110,6 +110,28 @@ Zope Installation Frequently Asked Questions
be added to the environment of the process when it is started be added to the environment of the process when it is started
by PCGI. by PCGI.
6. I have forgotten the only password used to access the site or
I have modified the security settings in such a way that even
I can't get access. How do I fix it?
Assuming you have write access to the directory where Zope is
installed, you can create a temporary "emergency user" using
the 'zpasswd.py' script::
python zpasswd.py access
Follow the prompts to enter a user name and password.
'zpasswd.py' will write the file named 'access'. Zope will
look for this file the next time it starts. After restarting,
browse to Zope's management interface and use the name and
password you entered.
As the emergency user, you are allowed to create user folders
and user accounts as well as adjust security settings but you
are not allowed to create objects like DTML methods or folders.
This is a safety precaution.
See more details in the file SECURITY.TXT.
Managing the Zope process Managing the Zope process
......
Setting the Zope "super manager" name and password Setting the initial user name and password
Because Zope is managed through the web, user names and passwords must be Because Zope is managed through the web, user names and passwords must be
used to assure that only authorized people can make changes to a Zope used to assure that only authorized people can make changes to a Zope
installation. User names and passwords are normally defined by creating installation.
and modifying user folders within Zope.
Some user name and password is needed to "bootstrap" the creation of
A special "super manager" user name and password are defined outside normal managers of your Zope site. This is accomplished through the
the application for two reasons use of the file 'inituser'. The first time Zope starts, it will detect
that no users have been defined in the root user folder. It will search
* Some user name and password is needed to "bootstrap" creation of for the 'inituser' file and, if it exists, will add the user defined
normal managers of your Zope site. in the file to the root user folder.
* The "super manager" provides an all-powerful user that can do Normally, 'inituser' is created by the Zope install scripts. Either
(almost) anything in the application, and whose password cannot the installer prompts for the password or a randomly generated
be changed through the application user interface. password is created and displayed at the end of the build script.
This user name and password is defined in the 'access' file located You can use the 'zpasswd.py' script to create 'inituser' yourself.
in the Zope directory. It should be readable only by the user Execute 'zpasswd.py' like this::
python zpasswd.py inituser
The script will prompt you for the name, password, and allowed
domains. The default is to encode the password with SHA, so please
remember this password as there is no way to recover it (although
'zpasswd.py' lets you reset it.)
In some situations you may need to bypass normal security controls
because you have lost your password or because the security settings
have been mixed up. Zope provides a facility called an "emergency
user" so that you can reset passwords and correct security
settings.
The emergency user password must be defined outside the application
user interface. It is defined in the 'access' file located
in the Zope directory. It should be readable only by the user
as which your web server runs. as which your web server runs.
The super manager username and password should only be used when To create the emergency user, use 'zpasswd.py' to create the
defining the normal management users and passwords and when dealing 'access' file like this::
with unusual situations, like lost (or hacked) manager user names and
passwords. python zpasswd.py access
In order to provide a somewhat higher level of security, various In order to provide a somewhat higher level of security, various
encoding schemes are supported which provide access to either SHA-1 encoding schemes are supported which provide access to either SHA-1
encryption or the standard UNIX crypt facility if it's been compiled encryption or the standard UNIX crypt facility if it has been compiled
into Python. Unless you have some special requirements (see below), into Python. Unless you have some special requirements (see below),
you should use the SHA-1 facility, which is the default. you should use the SHA-1 facility, which is the default.
The access file should consist of a single line of the form: Format of 'inituser' and 'access'
name:password A password file should consist of a single line of the form:
The build scripts automatically create an 'access' file for you, name:password
using a default username and a randomly generated password which
will be given at the end of the build script. The default is to
encode this with SHA, so please remember this password as there is no
way to recover it.
Note that you may also add an optional third component to the line Note that you may also add an optional third component to the line
in the access file to restrict super manager access by domain. in the access file to restrict access by domain.
For example, the line: For example, the line:
mario:nintendoRules:*.mydomain.com mario:nintendoRules:*.mydomain.com
in your 'access' file will only allow super manager access to your in your 'access' file will only allow permit emergency user access
installation from *.mydomain.com machines. Attempts to access the from *.mydomain.com machines. Attempts to access the system from
system from other domains will fail, even if the correct superuser other domains will fail, even if the correct emergency user name
name and password are used. and password are used.
Note that there is now a program to change the password, Please note that if you use the ZServer monitor capability, you will
'zpasswd.py', which if run will explain how to use it, and if run it need to run with a clear text password.
its most basic form will prompt for all information.
Please note that if you use the ZServer monitor capability, you will
need to run with a clear text password in this beta release.
Setting permissions on the var directory. Setting permissions on the var directory.
...@@ -73,3 +82,4 @@ Setting permissions on the var directory. ...@@ -73,3 +82,4 @@ Setting permissions on the var directory.
If you change the way you run Zope you may need to modify the permissions If you change the way you run Zope you may need to modify the permissions
of the var directory and the files in it to allow Zope to read and write of the var directory and the files in it to allow Zope to read and write
under its changed userid. under its changed userid.
...@@ -143,7 +143,7 @@ def main(args): ...@@ -143,7 +143,7 @@ def main(args):
import compilezpy import compilezpy
print '-'*78 print '-'*78
import zpasswd; zpasswd.write_access(home, user, group) import zpasswd; zpasswd.write_inituser(home, user, group)
import default_content; default_content.main(home, user, group) import default_content; default_content.main(home, user, group)
import make_resource; make_resource.main(home, pcgi, user, group) import make_resource; make_resource.main(home, pcgi, user, group)
import make_start; make_start.sh(home, user, group) import make_start; make_start.sh(home, user, group)
......
...@@ -85,8 +85,8 @@ ...@@ -85,8 +85,8 @@
__doc__='''Support for owned objects __doc__='''Support for owned objects
$Id: Owned.py,v 1.7 2000/11/09 14:14:09 chrism Exp $''' $Id: Owned.py,v 1.8 2000/12/05 18:49:42 shane Exp $'''
__version__='$Revision: 1.7 $'[11:-2] __version__='$Revision: 1.8 $'[11:-2]
import Globals, urlparse, SpecialUsers, ExtensionClass, string import Globals, urlparse, SpecialUsers, ExtensionClass, string
from AccessControl import getSecurityManager from AccessControl import getSecurityManager
...@@ -267,14 +267,14 @@ class Owned(ExtensionClass.Base): ...@@ -267,14 +267,14 @@ class Owned(ExtensionClass.Base):
else: else:
# Otherwise change the ownership # Otherwise change the ownership
user=getSecurityManager().getUser() user=getSecurityManager().getUser()
if aq_base(user) is SpecialUsers.super: if (SpecialUsers.emergency_user and
__creatable_by_super__=getattr(self, aq_base(user) is SpecialUsers.emergency_user):
'__creatable_by_super__', __creatable_by_emergency_user__=getattr(
None) self,'__creatable_by_emergency_user__', None)
if (__creatable_by_super__ is None or if (__creatable_by_emergency_user__ is None or
(not __creatable_by_super__())): (not __creatable_by_emergency_user__())):
raise SuperCannotOwn, ( raise EmergencyUserCannotOwn, (
"Objects cannot be owned by the superuser") "Objects cannot be owned by the emergency user")
self.changeOwnership(user) self.changeOwnership(user)
# Force all subs to acquire ownership! # Force all subs to acquire ownership!
...@@ -288,8 +288,8 @@ class Owned(ExtensionClass.Base): ...@@ -288,8 +288,8 @@ class Owned(ExtensionClass.Base):
Globals.default__class_init__(Owned) Globals.default__class_init__(Owned)
class SuperCannotOwn(Exception): class EmergencyUserCannotOwn(Exception):
"The superuser cannot own anything" "The emergency user cannot own anything"
class EditUnowned(Exception): class EditUnowned(Exception):
"Can't edit unowned executables" "Can't edit unowned executables"
......
...@@ -85,8 +85,8 @@ ...@@ -85,8 +85,8 @@
__doc__='''Objects that implement Permission-based roles. __doc__='''Objects that implement Permission-based roles.
$Id: PermissionRole.py,v 1.8 2000/11/20 10:51:21 jim Exp $''' $Id: PermissionRole.py,v 1.9 2000/12/05 18:49:42 shane Exp $'''
__version__='$Revision: 1.8 $'[11:-2] __version__='$Revision: 1.9 $'[11:-2]
import sys import sys
...@@ -134,6 +134,7 @@ class PermissionRole(Base): ...@@ -134,6 +134,7 @@ class PermissionRole(Base):
return r return r
# This is used when a permission maps explicitly to no permission.
_what_not_even_god_should_do=[] _what_not_even_god_should_do=[]
class imPermissionRole(Base): class imPermissionRole(Base):
......
...@@ -84,18 +84,18 @@ ...@@ -84,18 +84,18 @@
############################################################################## ##############################################################################
"""Access control package""" """Access control package"""
__version__='$Revision: 1.115 $'[11:-2] __version__='$Revision: 1.116 $'[11:-2]
import Globals, socket, regex, SpecialUsers import Globals, socket, regex, SpecialUsers
import os
from Globals import HTMLFile, MessageDialog, Persistent, PersistentMapping from Globals import HTMLFile, MessageDialog, Persistent, PersistentMapping
from string import join,strip,split,lower from string import join, strip, split, lower, upper
from App.Management import Navigation, Tabs from App.Management import Navigation, Tabs
from Acquisition import Implicit from Acquisition import Implicit
from OFS.SimpleItem import Item from OFS.SimpleItem import Item
from base64 import decodestring from base64 import decodestring
from App.ImageFile import ImageFile from App.ImageFile import ImageFile
from Role import RoleManager from Role import RoleManager
from string import split, join, upper
from PermissionRole import _what_not_even_god_should_do, rolesForPermissionOn from PermissionRole import _what_not_even_god_should_do, rolesForPermissionOn
from AuthEncoding import pw_validate from AuthEncoding import pw_validate
...@@ -187,7 +187,7 @@ class BasicUser(Implicit): ...@@ -187,7 +187,7 @@ class BasicUser(Implicit):
def authenticate(self, password, request): def authenticate(self, password, request):
passwrd=self._getPassword() passwrd=self._getPassword()
result = pw_validate(passwrd, password) result = pw_validate(passwrd, password)
domains=self.getDomains() domains=self.getDomains()
if domains: if domains:
return result and domainSpecMatch(domains, request) return result and domainSpecMatch(domains, request)
...@@ -300,14 +300,15 @@ class SimpleUser(BasicUser): ...@@ -300,14 +300,15 @@ class SimpleUser(BasicUser):
return tuple(self.domains) return tuple(self.domains)
class SpecialUser(SimpleUser): class SpecialUser(SimpleUser):
"""Class for special users, like super and nobody""" """Class for special users, like emergency user and nobody"""
def getId(self): pass def getId(self): pass
class User(SimpleUser, Persistent): class User(SimpleUser, Persistent):
"""Standard User object""" """Standard User object"""
class Super(SpecialUser): class UnrestrictedUser(SpecialUser):
"""Super user """User that passes all security checks. Note, however, that modules
like Owner.py can still impose restrictions.
""" """
def allowed(self,parent,roles=None): def allowed(self,parent,roles=None):
return roles is not _what_not_even_god_should_do return roles is not _what_not_even_god_should_do
...@@ -318,32 +319,52 @@ class Super(SpecialUser): ...@@ -318,32 +319,52 @@ class Super(SpecialUser):
def has_permission(self, permission, object): return 1 def has_permission(self, permission, object): return 1
def readUserAccessFile(filename):
'''Reads an access file from INSTANCE_HOME.
Returns name, password, domains, remote_user_mode.
'''
try:
f = open(os.path.join(INSTANCE_HOME, filename), 'r')
line = f.readline()
f.close()
except IOError:
return None
if line:
data = split(strip(line), ':')
remote_user_mode = not data[1]
try: ds = split(data[2], ' ')
except: ds = []
return data[0], data[1], ds, remote_user_mode
else:
return None
# Create emergency user.
_remote_user_mode=0 _remote_user_mode=0
try:
f=open('%s/access' % INSTANCE_HOME, 'r') info = readUserAccessFile('access')
except IOError: if info:
raise 'InstallError', ( _remote_user_mode = info[3]
'No access file found at %s - see INSTALL.txt' % INSTANCE_HOME emergency_user = UnrestrictedUser(
) info[0], info[1], ('manage',), info[2])
try: else:
data=split(strip(f.readline()),':') emergency_user = None
f.close()
_remote_user_mode=not data[1] super = emergency_user # Note: use of the 'super' name is deprecated.
try: ds=split(data[2], ' ') del info
except: ds=[]
super=Super(data[0],data[1],('manage',), ds)
del data
except:
raise 'InstallError', 'Invalid format for access file - see INSTALL.txt'
nobody=SpecialUser('Anonymous User','',('Anonymous',), []) nobody=SpecialUser('Anonymous User','',('Anonymous',), [])
system=Super('System Processes','',('manage',), []) system=UnrestrictedUser('System Processes','',('manage',), [])
# stuff these in a handier place for importing # stuff these in a handier place for importing
SpecialUsers.nobody=nobody SpecialUsers.nobody=nobody
SpecialUsers.system=system SpecialUsers.system=system
SpecialUsers.super=super SpecialUsers.emergency_user=emergency_user
# Note: use of the 'super' name is deprecated.
SpecialUsers.super=emergency_user
class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager, class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
...@@ -417,9 +438,11 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager, ...@@ -417,9 +438,11 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
_remote_user_mode=_remote_user_mode _remote_user_mode=_remote_user_mode
_super=super _emergency_user=emergency_user
# Note: use of the '_super' name is deprecated.
_super=emergency_user
_nobody=nobody _nobody=nobody
def validate(self,request,auth='',roles=None): def validate(self,request,auth='',roles=None):
if roles is _what_not_even_god_should_do: if roles is _what_not_even_god_should_do:
...@@ -452,11 +475,12 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager, ...@@ -452,11 +475,12 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
return None return None
name,password=tuple(split(decodestring(split(auth)[-1]), ':', 1)) name,password=tuple(split(decodestring(split(auth)[-1]), ':', 1))
# Check for superuser # Check for emergency user
super=self._super emergency_user=self._emergency_user
if self._isTop() and (name==super.getUserName()) and \ if (emergency_user and self._isTop() and (
super.authenticate(password, request): name == emergency_user.getUserName())
return super and emergency_user.authenticate(password, request)):
return emergency_user
# Try to get user # Try to get user
user=self.getUser(name) user=self.getUser(name)
...@@ -520,10 +544,11 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager, ...@@ -520,10 +544,11 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
return ob return ob
return None return None
# Check for superuser # Check for emergency user
super=self._super emergency_user=self._emergency_user
if self._isTop() and (name==super.getUserName()): if (emergency_user and self._isTop() and
return super name==emergency_user.getUserName()):
return emergency_user
# Try to get user # Try to get user
user=self.getUser(name) user=self.getUser(name)
...@@ -572,7 +597,8 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager, ...@@ -572,7 +597,8 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
title ='Illegal value', title ='Illegal value',
message='Password and confirmation must be specified', message='Password and confirmation must be specified',
action ='manage_main') action ='manage_main')
if self.getUser(name) or (name==self._super.getUserName()): if self.getUser(name) or (self._emergency_user and
name == self._emergency_user.getUserName()):
return MessageDialog( return MessageDialog(
title ='Illegal value', title ='Illegal value',
message='A user with the specified name already exists', message='A user with the specified name already exists',
...@@ -690,7 +716,7 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager, ...@@ -690,7 +716,7 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
if hasattr(self, 'aq_base'): self=self.aq_base if hasattr(self, 'aq_base'): self=self.aq_base
container.__allow_groups__=self container.__allow_groups__=self
def __creatable_by_super__(self): return 1 def __creatable_by_emergency_user__(self): return 1
def _setId(self, id): def _setId(self, id):
if id != self.id: if id != self.id:
...@@ -759,6 +785,22 @@ class UserFolder(BasicUserFolder): ...@@ -759,6 +785,22 @@ class UserFolder(BasicUserFolder):
for name in names: for name in names:
del self.data[name] del self.data[name]
def _createInitialUser(self):
"""
If there are no users in this user folder,
populates from the 'inituser' file in INSTANCE_HOME.
Called only by OFS.Application.initialize().
"""
if len(self.data) < 1:
info = readUserAccessFile('inituser')
if info:
name, password, domains, remote_user_mode = info
self._doAddUser(name, password, ('Manager',), domains)
try:
os.remove(os.path.join(INSTANCE_HOME, 'inituser'))
except:
pass
Globals.default__class_init__(UserFolder) Globals.default__class_init__(UserFolder)
......
...@@ -85,8 +85,8 @@ ...@@ -85,8 +85,8 @@
__doc__='''Application support __doc__='''Application support
$Id: Application.py,v 1.133 2000/09/07 16:07:20 brian Exp $''' $Id: Application.py,v 1.134 2000/12/05 18:49:43 shane Exp $'''
__version__='$Revision: 1.133 $'[11:-2] __version__='$Revision: 1.134 $'[11:-2]
import Globals,Folder,os,sys,App.Product, App.ProductRegistry, misc_ import Globals,Folder,os,sys,App.Product, App.ProductRegistry, misc_
import time, traceback, os, string, Products import time, traceback, os, string, Products
...@@ -186,7 +186,7 @@ class Application(Globals.ApplicationDefaultPermissions, ...@@ -186,7 +186,7 @@ class Application(Globals.ApplicationDefaultPermissions,
'Control_Panel') 'Control_Panel')
# This class-default __allow_groups__ ensures that the # This class-default __allow_groups__ ensures that the
# superuser can still access the system if the top-level # emergency user can still access the system if the top-level
# UserFolder is deleted. This is necessary to allow people # UserFolder is deleted. This is necessary to allow people
# to replace the top-level UserFolder object. # to replace the top-level UserFolder object.
...@@ -362,6 +362,14 @@ def initialize(app): ...@@ -362,6 +362,14 @@ def initialize(app):
get_transaction().note('Added Globals') get_transaction().note('Added Globals')
get_transaction().commit() get_transaction().commit()
# Install the initial user.
if hasattr(app, 'acl_users'):
users = app.acl_users
if hasattr(users, '_createInitialUser'):
app.acl_users._createInitialUser()
get_transaction().note('Created initial user')
get_transaction().commit()
install_products(app) install_products(app)
def import_products(_st=type('')): def import_products(_st=type('')):
......
...@@ -104,7 +104,7 @@ def main(me): ...@@ -104,7 +104,7 @@ def main(me):
import build_extensions import build_extensions
user=group='' user=group=''
import default_content; default_content.main(home, user, group) import default_content; default_content.main(home, user, group)
import zpasswd; zpasswd.write_access(home, user, group) import zpasswd; zpasswd.write_inituser(home, user, group)
pcgi=os.path.join(home, 'Zope.cgi') pcgi=os.path.join(home, 'Zope.cgi')
import make_start; make_start.sh(home, user, group) import make_start; make_start.sh(home, user, group)
......
...@@ -204,8 +204,8 @@ Options: ...@@ -204,8 +204,8 @@ Options:
allows interactive Python style access to a running ZServer. To allows interactive Python style access to a running ZServer. To
access the server see medusa/monitor_client.py or access the server see medusa/monitor_client.py or
medusa/monitor_client_win32.py. The monitor server password is the medusa/monitor_client_win32.py. The monitor server password is the
same as the Zope super manager password set in the 'access' same as the Zope emergency user password set in the 'access'
file. The default is %(MONITOR_PORT)s. file. The default is to not start up a monitor server.
The port can be preeceeded by an ip address follwed by a colon The port can be preeceeded by an ip address follwed by a colon
to specify an address to listen on. This allows different servers to specify an address to listen on. This allows different servers
...@@ -337,7 +337,7 @@ FTP_PORT=8021 ...@@ -337,7 +337,7 @@ FTP_PORT=8021
PCGI_FILE='Zope.cgi' PCGI_FILE='Zope.cgi'
## Monitor configuration ## Monitor configuration
MONITOR_PORT=8099 MONITOR_PORT=0
# Module to be published, which must be Main or Zope # Module to be published, which must be Main or Zope
MODULE='Zope' MODULE='Zope'
...@@ -444,7 +444,6 @@ try: ...@@ -444,7 +444,6 @@ try:
elif o=='-f': elif o=='-f':
FTP_PORT=server_info(FTP_PORT, v) FTP_PORT=server_info(FTP_PORT, v)
elif o=='-P': elif o=='-P':
MONITOR_PORT=server_info(MONITOR_PORT, v, 99)
HTTP_PORT=server_info(HTTP_PORT, v, 80) HTTP_PORT=server_info(HTTP_PORT, v, 80)
FTP_PORT=server_info(FTP_PORT, v, 21) FTP_PORT=server_info(FTP_PORT, v, 21)
...@@ -663,14 +662,21 @@ if FCGI_PORT and not READ_ONLY: ...@@ -663,14 +662,21 @@ if FCGI_PORT and not READ_ONLY:
# Monitor Server # Monitor Server
if MONITOR_PORT: if MONITOR_PORT:
if type(MONITOR_PORT) is type(0): from AccessControl.User import emergency_user
MONITOR_PORT=((IP_ADDRESS, MONITOR_PORT),) if emergency_user:
for address, port in MONITOR_PORT: pw = emergency_user._getPassword()
from AccessControl.User import super else:
monitor=secure_monitor_server( pw = None
password=super._getPassword(), zLOG.LOG("z2", zLOG.WARNING, 'Monitor server not started'
hostname=address, ' because no emergency user exists.')
port=port) if pw:
if type(MONITOR_PORT) is type(0):
MONITOR_PORT=((IP_ADDRESS, MONITOR_PORT),)
for address, port in MONITOR_PORT:
monitor=secure_monitor_server(
password=pw,
hostname=address,
port=port)
# Try to set uid to "-u" -provided uid. # Try to set uid to "-u" -provided uid.
# Try to set gid to "-u" user's primary group. # Try to set gid to "-u" user's primary group.
...@@ -718,11 +724,3 @@ if not READ_ONLY: ...@@ -718,11 +724,3 @@ if not READ_ONLY:
sys.ZServerExitCode=0 sys.ZServerExitCode=0
asyncore.loop() asyncore.loop()
sys.exit(sys.ZServerExitCode) sys.exit(sys.ZServerExitCode)
...@@ -83,9 +83,9 @@ ...@@ -83,9 +83,9 @@
# attributions are listed in the accompanying credits file. # attributions are listed in the accompanying credits file.
# #
############################################################################## ##############################################################################
"""Zope password change system""" """Zope user bootstrap system"""
__version__='$Revision: 1.10 $ '[11:-2] __version__='$Revision: 1.11 $ '[11:-2]
import sys, string, sha, binascii, whrandom, getopt, getpass, os import sys, string, sha, binascii, whrandom, getopt, getpass, os
...@@ -112,29 +112,31 @@ def generate_passwd(password, encoding): ...@@ -112,29 +112,31 @@ def generate_passwd(password, encoding):
return pw return pw
def write_access(home, user='', group=''): def write_generated_password(home, ac_path, username):
import whrandom import whrandom
pw_choices = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ pw_choices = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz" \ "abcdefghijklmnopqrstuvwxyz" \
"0123456789!" "0123456789!"
acfile=open(ac_path, 'w')
pw = ''
for i in range(8):
pw = pw + whrandom.choice(pw_choices)
acfile.write('%s:%s' % (username, generate_passwd(pw, 'SHA')))
acfile.close()
os.system('chmod 644 %s' % ac_path)
return pw
def write_access(home, user='', group=''):
ac_path=os.path.join(home, 'access') ac_path=os.path.join(home, 'access')
if not os.path.exists(ac_path): if not os.path.exists(ac_path):
print '-'*78 print '-'*78
print 'creating default access file' print 'creating default access file'
acfile=open(ac_path, 'w') pw = write_generated_password(home, ac_path, 'emergency')
pw = ''
for i in range(8):
pw = pw + whrandom.choice(pw_choices)
acfile.write('superuser:' + generate_passwd(pw, 'SHA'))
acfile.close()
os.system('chmod 644 access')
print """Note: print """Note:
The super user name and password are 'superuser' The emergency user name and password are 'emergency'
and '%s'. and '%s'.
You can change the superuser name and password with the You can change the emergency name and password with the
zpasswd script. To find out more, type: zpasswd script. To find out more, type:
%s zpasswd.py %s zpasswd.py
...@@ -142,6 +144,23 @@ def write_access(home, user='', group=''): ...@@ -142,6 +144,23 @@ def write_access(home, user='', group=''):
import do; do.ch(ac_path, user, group) 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 main(argv): def main(argv):
short_options = ':u:p:e:d:' short_options = ':u:p:e:d:'
long_options = ['username=', long_options = ['username=',
...@@ -149,13 +168,12 @@ def main(argv): ...@@ -149,13 +168,12 @@ def main(argv):
'encoding=', 'encoding=',
'domains='] 'domains=']
usage = """%s [options] filename usage = """Usage: %s [options] filename
If this program is called without command-line options, it will prompt If this program is called without command-line options, it will prompt
for all necessary information. The available options are: for all necessary information. The available options are:
-u / --username= -u / --username=
Set the username to be used for the superuser Set the username to be used for the initial user or the emergency user
-p / --password= -p / --password=
Set the password Set the password
...@@ -167,10 +185,10 @@ for all necessary information. The available options are: ...@@ -167,10 +185,10 @@ for all necessary information. The available options are:
Set the domain names that the user user can log in from. Defaults to Set the domain names that the user user can log in from. Defaults to
any. OPTIONAL. any. OPTIONAL.
Filename is required, and should be the name of the file to store the Filename is required and should be the name of the file to store the
information in (usually "access"). information in (usually "inituser" or "access").
Copyright (C) 1999 Digital Creations, Inc. Copyright (C) 1999, 2000 Digital Creations, Inc.
""" % argv[0] """ % argv[0]
try: try:
...@@ -186,7 +204,7 @@ Copyright (C) 1999 Digital Creations, Inc. ...@@ -186,7 +204,7 @@ Copyright (C) 1999 Digital Creations, Inc.
if len(optlist) > 0: if len(optlist) > 0:
# Set the sane defaults # Set the sane defaults
username = 'superuser' username = ''
encoding = 'SHA' encoding = 'SHA'
domains = '' domains = ''
...@@ -240,8 +258,8 @@ CLEARTEXT - no protection. ...@@ -240,8 +258,8 @@ CLEARTEXT - no protection.
if domains: domains = ":" + domains if domains: domains = ":" + domains
access_file.write(username + ":" + access_file.write(username + ":" +
generate_passwd(password, encoding) + generate_passwd(password, encoding) +
domains) domains)
except "CommandLineError": except "CommandLineError":
sys.stderr.write(usage) sys.stderr.write(usage)
......
Markdown is supported
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