[Zope-Checkins] SVN: Zope/trunk/src/ Split out ZMI related parts of user folders and move it to OFS

Hanno Schlichting hannosch at hannosch.eu
Sat Jun 19 10:57:58 EDT 2010


Log message for revision 113646:
  Split out ZMI related parts of user folders and move it to OFS
  

Changed:
  U   Zope/trunk/src/AccessControl/User.py
  D   Zope/trunk/src/AccessControl/dtml/
  U   Zope/trunk/src/AccessControl/interfaces.py
  U   Zope/trunk/src/AccessControl/tests/testOwned.py
  U   Zope/trunk/src/AccessControl/tests/testZopeSecurityPolicy.py
  A   Zope/trunk/src/AccessControl/tests/test_userfolder.py
  U   Zope/trunk/src/AccessControl/userfolder.py
  U   Zope/trunk/src/OFS/Application.py
  A   Zope/trunk/src/OFS/dtml/addUser.dtml
  A   Zope/trunk/src/OFS/dtml/editUser.dtml
  A   Zope/trunk/src/OFS/dtml/mainUser.dtml
  A   Zope/trunk/src/OFS/dtml/userFolderProps.dtml
  U   Zope/trunk/src/OFS/role.py
  D   Zope/trunk/src/OFS/tests/testUserFolder.py
  A   Zope/trunk/src/OFS/tests/test_userfolder.py
  A   Zope/trunk/src/OFS/userfolder.py
  U   Zope/trunk/src/Products/OFSP/__init__.py
  U   Zope/trunk/src/Testing/ZopeTestCase/ZopeTestCase.py
  U   Zope/trunk/src/Testing/ZopeTestCase/testPortalTestCase.py
  U   Zope/trunk/src/Testing/ZopeTestCase/testZopeTestCase.py

-=-
Modified: Zope/trunk/src/AccessControl/User.py
===================================================================
--- Zope/trunk/src/AccessControl/User.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/AccessControl/User.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -34,6 +34,12 @@
 from .users import reqattr
 from .users import UnrestrictedUser as Super
 
-from .userfolder import BasicUserFolder
-from .userfolder import UserFolder
-from .userfolder import manage_addUserFolder
+
+from zope.deferredimport import deprecated
+deprecated("User folders are no longer part of AccessControl, please depend "
+           "on Zope2 and import from OFS.userfolder or use the new minimal "
+           "user folder classes from AccessControl.userfolder.",
+    BasicUserFolder = 'OFS.userfolder:BasicUserFolder',
+    manage_addUserFolder = 'OFS.userfolder:manage_addUserFolder',
+    UserFolder = 'OFS.userfolder:UserFolder',
+)

Modified: Zope/trunk/src/AccessControl/interfaces.py
===================================================================
--- Zope/trunk/src/AccessControl/interfaces.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/AccessControl/interfaces.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -197,6 +197,7 @@
             'disallowed_permissions' -> all other permissions 
         """
 
+
 class IStandardUserFolder(Interface):
 
     def getUser(name):
@@ -213,6 +214,7 @@
         """Get a sequence of names of the users which reside in the user folder.
         """
 
+
 class ISecurityPolicy(Interface):
     """Plug-in policy for checking access to objects within untrusted code.
     """

Modified: Zope/trunk/src/AccessControl/tests/testOwned.py
===================================================================
--- Zope/trunk/src/AccessControl/tests/testOwned.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/AccessControl/tests/testOwned.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -197,7 +197,7 @@
 
     def setUp(self):
         from AccessControl.owner import UnownableOwner
-        from AccessControl.User import UserFolder
+        from AccessControl.userfolder import UserFolder
         super(OwnershipChangeTests, self).setUp()
 
         self.root = FauxRoot()

Modified: Zope/trunk/src/AccessControl/tests/testZopeSecurityPolicy.py
===================================================================
--- Zope/trunk/src/AccessControl/tests/testZopeSecurityPolicy.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/AccessControl/tests/testZopeSecurityPolicy.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -167,8 +167,8 @@
         uf = UserFolder()
         a.acl_users = uf
         self.uf = a.acl_users
-        uf._addUser('joe', 'password', 'password', user_roles, ())
-        uf._addUser('theowner', 'password', 'password', eo_roles, ())
+        uf._doAddUser('joe', 'password', user_roles, ())
+        uf._doAddUser('theowner', 'password', eo_roles, ())
         user = uf.getUserById('joe')
         self.user = user
         context = SecurityContext(user)
@@ -307,8 +307,8 @@
         self.a.subobject = ImplictAcqObject()
         subobject = self.a.subobject
         subobject.acl_users = UserFolder()
-        subobject.acl_users._addUser('theowner', 'password', 'password', 
-                                      eo_roles + sysadmin_roles, ())
+        subobject.acl_users._doAddUser('theowner', 'password', 
+                                       eo_roles + sysadmin_roles, ())
         subobject.r_item = RestrictedSimpleItem()
         r_subitem = subobject.r_item
         r_subitem.owned_setuid_m = OwnedSetuidMethod()
@@ -353,8 +353,8 @@
         self.a.subobject = ImplictAcqObject()
         subobject = self.a.subobject
         subobject.acl_users = UserFolder()
-        subobject.acl_users._addUser('theowner', 'password', 'password', 
-                                      eo_roles + sysadmin_roles, ())
+        subobject.acl_users._doAddUser('theowner', 'password',
+                                       eo_roles + sysadmin_roles, ())
         subobject.item = UnprotectedSimpleItem()
         subitem = subobject.item
         subitem.owned_setuid_m = OwnedSetuidMethod()

Copied: Zope/trunk/src/AccessControl/tests/test_userfolder.py (from rev 113633, Zope/trunk/src/OFS/tests/testUserFolder.py)
===================================================================
--- Zope/trunk/src/AccessControl/tests/test_userfolder.py	                        (rev 0)
+++ Zope/trunk/src/AccessControl/tests/test_userfolder.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -0,0 +1,176 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+""" Unit tests for AccessControl.User
+"""
+import unittest
+
+# TODO class Test_readUserAccessFile(unittest.TestCase)
+
+
+# TODO class BasicUserFoldertests(unittest.TestCase)
+
+
+class UserFolderTests(unittest.TestCase):
+
+    def setUp(self):
+        import transaction
+        transaction.begin()
+
+    def tearDown(self):
+        import transaction
+        from AccessControl.SecurityManagement import noSecurityManager
+        noSecurityManager()
+        transaction.abort()
+
+    def _getTargetClass(self):
+        from AccessControl.userfolder import UserFolder
+        return UserFolder
+
+    def _makeOne(self):
+        uf = self._getTargetClass()()
+        uf._doAddUser('user1', 'secret', ['role1'], [])
+        return uf
+
+    def _makeBasicAuthToken(self, creds='user1:secret'):
+        import base64
+        return 'Basic %s' % base64.encodestring(creds)
+
+    def _login(self, uf, name):
+        from AccessControl.SecurityManagement import newSecurityManager
+        user = uf.getUserById(name)
+        user = user.__of__(uf)
+        newSecurityManager(None, user)
+
+    def test_class_conforms_to_IStandardUserFolder(self):
+        from AccessControl.interfaces import IStandardUserFolder
+        from zope.interface.verify import verifyClass
+        verifyClass(IStandardUserFolder, self._getTargetClass())
+
+    def testGetUser(self):
+        uf = self._makeOne()
+        self.failIfEqual(uf.getUser('user1'), None)
+
+    def testGetBadUser(self):
+        uf = self._makeOne()
+        self.assertEqual(uf.getUser('user2'), None)
+
+    def testGetUserById(self):
+        uf = self._makeOne()
+        self.failIfEqual(uf.getUserById('user1'), None)
+
+    def testGetBadUserById(self):
+        uf = self._makeOne()
+        self.assertEqual(uf.getUserById('user2'), None)
+
+    def testGetUsers(self):
+        uf = self._makeOne()
+        users = uf.getUsers()
+        self.failUnless(users)
+        self.assertEqual(users[0].getUserName(), 'user1')
+
+    def testGetUserNames(self):
+        uf = self._makeOne()
+        names = uf.getUserNames()
+        self.failUnless(names)
+        self.assertEqual(names[0], 'user1')
+
+    def testIdentify(self):
+        uf = self._makeOne()
+        name, password = uf.identify(self._makeBasicAuthToken())
+        self.assertEqual(name, 'user1')
+        self.assertEqual(password, 'secret')
+
+    def testGetRoles(self):
+        uf = self._makeOne()
+        user = uf.getUser('user1')
+        self.failUnless('role1' in user.getRoles())
+
+    def testMaxListUsers(self):
+        # create a folder-ish thing which contains a roleManager,
+        # then put an acl_users object into the folde-ish thing
+        from AccessControl.userfolder import BasicUserFolder
+
+        class Folderish(BasicUserFolder):
+            def __init__(self, size, count):
+                self.maxlistusers = size
+                self.users = []
+                self.acl_users = self
+                self.__allow_groups__ = self
+                for i in xrange(count):
+                    self.users.append("Nobody")
+
+            def getUsers(self):
+                return self.users
+
+            def user_names(self):
+                return self.getUsers()
+
+
+        tinyFolderOver = Folderish(15, 20)
+        tinyFolderUnder = Folderish(15, 10)
+
+        assert tinyFolderOver.maxlistusers == 15
+        assert tinyFolderUnder.maxlistusers == 15
+        assert len(tinyFolderOver.user_names()) == 20
+        assert len(tinyFolderUnder.user_names()) == 10
+
+        try:
+            list = tinyFolderOver.get_valid_userids()
+            assert 0, "Did not raise overflow error"
+        except OverflowError:
+            pass
+
+        try:
+            list = tinyFolderUnder.get_valid_userids()
+            pass
+        except OverflowError:
+            assert 0, "Raised overflow error erroneously"
+
+    def test__doAddUser_with_not_yet_encrypted_passwords(self):
+        # See collector #1869 && #1926
+        from AccessControl.AuthEncoding import pw_validate
+
+        USER_ID = 'not_yet_encrypted'
+        PASSWORD = 'password'
+
+        uf = self._makeOne()
+        uf.encrypt_passwords = True
+        self.failIf(uf._isPasswordEncrypted(PASSWORD))
+
+        uf._doAddUser(USER_ID, PASSWORD, [], [])
+        user = uf.getUserById(USER_ID)
+        self.failUnless(uf._isPasswordEncrypted(user.__))
+        self.failUnless(pw_validate(user.__, PASSWORD))
+
+    def test__doAddUser_with_preencrypted_passwords(self):
+        # See collector #1869 && #1926
+        from AccessControl.AuthEncoding import pw_validate
+
+        USER_ID = 'already_encrypted'
+        PASSWORD = 'password'
+
+        uf = self._makeOne()
+        uf.encrypt_passwords = True
+        ENCRYPTED = uf._encryptPassword(PASSWORD)
+
+        uf._doAddUser(USER_ID, ENCRYPTED, [], [])
+        user = uf.getUserById(USER_ID)
+        self.assertEqual(user.__, ENCRYPTED)
+        self.failUnless(uf._isPasswordEncrypted(user.__))
+        self.failUnless(pw_validate(user.__, PASSWORD))
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(UserFolderTests))
+    return suite

Modified: Zope/trunk/src/AccessControl/userfolder.py
===================================================================
--- Zope/trunk/src/AccessControl/userfolder.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/AccessControl/userfolder.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -10,10 +10,9 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Access control package.
+"""User folders.
 """
 
-import os
 from base64 import decodestring
 
 from Acquisition import aq_base
@@ -25,37 +24,26 @@
 from zExceptions import Unauthorized
 from zope.interface import implements
 
-# TODO dependencies
-from App.Management import Navigation
-from App.Management import Tabs
-from App.special_dtml import DTMLFile
-from App.Dialogs import MessageDialog
-from OFS.role import RoleManager
-from OFS.SimpleItem import Item
-
 from AccessControl import AuthEncoding
 from AccessControl import ClassSecurityInfo
 from AccessControl.class_init import InitializeClass
 from AccessControl.interfaces import IStandardUserFolder
 from AccessControl.Permissions import manage_users as ManageUsers
-from AccessControl.requestmethod import requestmethod
 from AccessControl.rolemanager import DEFAULTMAXLISTUSERS
+from AccessControl.rolemanager import RoleManager
 from AccessControl.SecurityManagement import getSecurityManager
 from AccessControl.SecurityManagement import newSecurityManager
 from AccessControl.SecurityManagement import noSecurityManager
 from AccessControl.users import User
-from AccessControl.users import readUserAccessFile
 from AccessControl.users import _remote_user_mode
 from AccessControl.users import emergency_user
 from AccessControl.users import nobody
 from AccessControl.users import addr_match
 from AccessControl.users import host_match
-from AccessControl.users import reqattr
 from AccessControl.ZopeSecurityPolicy import _noroles
 
 
-class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
-                      Item):
+class BasicUserFolder(Implicit, Persistent, RoleManager):
     """Base class for UserFolder-like objects"""
 
     meta_type = 'User Folder'
@@ -67,21 +55,13 @@
     maxlistusers = DEFAULTMAXLISTUSERS
     encrypt_passwords = 1
 
+    _remote_user_mode = _remote_user_mode
+    _domain_auth_mode = 0
+    _emergency_user = emergency_user
+    _nobody = nobody
+
     security = ClassSecurityInfo()
 
-    manage_options=(
-        (
-        {'label': 'Contents', 'action': 'manage_main'},
-        {'label': 'Properties', 'action': 'manage_userFolderProperties'},
-        )
-        +RoleManager.manage_options
-        +Item.manage_options
-        )
-
-    # ----------------------------------
-    # Public UserFolder object interface
-    # ----------------------------------
-
     security.declareProtected(ManageUsers, 'getUserNames')
     def getUserNames(self):
         """Return a list of usernames"""
@@ -127,60 +107,6 @@
            to do the actual deleting of users."""
         raise NotImplementedError
 
-    # As of Zope 2.5, userFolderAddUser, userFolderEditUser and
-    # userFolderDelUsers offer aliases for the the _doAddUser, _doChangeUser
-    # and _doDelUsers methods (with the difference that they can be called
-    # from XML-RPC or untrusted scripting code, given the necessary
-    # permissions).
-    #
-    # Authors of custom user folders don't need to do anything special to
-    # support these - they will just call the appropriate '_' methods that
-    # user folder subclasses already implement.
-
-    security.declareProtected(ManageUsers, 'userFolderAddUser')
-    @requestmethod('POST')
-    def userFolderAddUser(self, name, password, roles, domains,
-                          REQUEST=None, **kw):
-        """API method for creating a new user object. Note that not all
-           user folder implementations support dynamic creation of user
-           objects."""
-        if hasattr(self, '_doAddUser'):
-            return self._doAddUser(name, password, roles, domains, **kw)
-        raise NotImplementedError
-
-    security.declareProtected(ManageUsers, 'userFolderEditUser')
-    @requestmethod('POST')
-    def userFolderEditUser(self, name, password, roles, domains,
-                           REQUEST=None, **kw):
-        """API method for changing user object attributes. Note that not
-           all user folder implementations support changing of user object
-           attributes."""
-        if hasattr(self, '_doChangeUser'):
-            return self._doChangeUser(name, password, roles, domains, **kw)
-        raise NotImplementedError
-
-    security.declareProtected(ManageUsers, 'userFolderDelUsers')
-    @requestmethod('POST')
-    def userFolderDelUsers(self, names, REQUEST=None):
-        """API method for deleting one or more user objects. Note that not
-           all user folder implementations support deletion of user objects."""
-        if hasattr(self, '_doDelUsers'):
-            return self._doDelUsers(names)
-        raise NotImplementedError
-
-
-    # -----------------------------------
-    # Private UserFolder object interface
-    # -----------------------------------
-
-    _remote_user_mode=_remote_user_mode
-    _domain_auth_mode=0
-    _emergency_user=emergency_user
-    # Note: use of the '_super' name is deprecated.
-    _super=emergency_user
-    _nobody=nobody
-
-
     def identify(self, auth):
         if auth and auth.lower().startswith('basic '):
             try:
@@ -389,67 +315,12 @@
     def __len__(self):
         return 1
 
-    _mainUser=DTMLFile('dtml/mainUser', globals())
-    _add_User=DTMLFile('dtml/addUser', globals(),
-                       remote_user_mode__=_remote_user_mode)
-    _editUser=DTMLFile('dtml/editUser', globals(),
-                       remote_user_mode__=_remote_user_mode)
-    manage=manage_main=_mainUser
-    manage_main._setName('manage_main')
-
-    _userFolderProperties = DTMLFile('dtml/userFolderProps', globals())
-
-    def manage_userFolderProperties(self, REQUEST=None,
-                                    manage_tabs_message=None):
-        """
-        """
-        return self._userFolderProperties(
-            self, REQUEST, manage_tabs_message=manage_tabs_message,
-            management_view='Properties')
-
-    @requestmethod('POST')
-    def manage_setUserFolderProperties(self, encrypt_passwords=0,
-                                       update_passwords=0,
-                                       maxlistusers=DEFAULTMAXLISTUSERS,
-                                       REQUEST=None):
-        """
-        Sets the properties of the user folder.
-        """
-        self.encrypt_passwords = not not encrypt_passwords
-        try:
-            self.maxlistusers = int(maxlistusers)
-        except ValueError:
-            self.maxlistusers = DEFAULTMAXLISTUSERS
-        if encrypt_passwords and update_passwords:
-            changed = 0
-            for u in self.getUsers():
-                pw = u._getPassword()
-                if not self._isPasswordEncrypted(pw):
-                    pw = self._encryptPassword(pw)
-                    self._doChangeUser(u.getUserName(), pw, u.getRoles(),
-                                       u.getDomains())
-                    changed = changed + 1
-            if REQUEST is not None:
-                if not changed:
-                    msg = 'All passwords already encrypted.'
-                else:
-                    msg = 'Encrypted %d password(s).' % changed
-                return self.manage_userFolderProperties(
-                    REQUEST, manage_tabs_message=msg)
-            else:
-                return changed
-        else:
-            if REQUEST is not None:
-                return self.manage_userFolderProperties(
-                    REQUEST, manage_tabs_message='Saved changes.')
-
     def _isPasswordEncrypted(self, pw):
         return AuthEncoding.is_encrypted(pw)
 
     def _encryptPassword(self, pw):
         return AuthEncoding.pw_encrypt(pw, 'SSHA')
 
-
     def domainSpecValidate(self, spec):
         for ob in spec:
             am = addr_match(ob)
@@ -458,168 +329,13 @@
                 return 0
         return 1
 
-    @requestmethod('POST')
-    def _addUser(self, name, password, confirm, roles, domains, REQUEST=None):
-        if not name:
-            return MessageDialog(
-                   title='Illegal value',
-                   message='A username must be specified',
-                   action='manage_main')
-        if not password or not confirm:
-            if not domains:
-                return MessageDialog(
-                   title='Illegal value',
-                   message='Password and confirmation must be specified',
-                   action='manage_main')
-        if self.getUser(name) or (self._emergency_user and
-                                  name == self._emergency_user.getUserName()):
-            return MessageDialog(
-                   title='Illegal value',
-                   message='A user with the specified name already exists',
-                   action='manage_main')
-        if (password or confirm) and (password != confirm):
-            return MessageDialog(
-                   title='Illegal value',
-                   message='Password and confirmation do not match',
-                   action='manage_main')
-
-        if not roles:
-            roles = []
-        if not domains:
-            domains = []
-
-        if domains and not self.domainSpecValidate(domains):
-            return MessageDialog(
-                   title='Illegal value',
-                   message='Illegal domain specification',
-                   action='manage_main')
-        self._doAddUser(name, password, roles, domains)
-        if REQUEST:
-            return self._mainUser(self, REQUEST)
-
-    @requestmethod('POST')
-    def _changeUser(self, name, password, confirm, roles, domains,
-                    REQUEST=None):
-        if password == 'password' and confirm == 'pconfirm':
-            # Protocol for editUser.dtml to indicate unchanged password
-            password = confirm = None
-        if not name:
-            return MessageDialog(
-                   title='Illegal value',
-                   message='A username must be specified',
-                   action='manage_main')
-        if password == confirm == '':
-            if not domains:
-                return MessageDialog(
-                   title='Illegal value',
-                   message='Password and confirmation must be specified',
-                   action='manage_main')
-        if not self.getUser(name):
-            return MessageDialog(
-                   title='Illegal value',
-                   message='Unknown user',
-                   action='manage_main')
-        if (password or confirm) and (password != confirm):
-            return MessageDialog(
-                   title='Illegal value',
-                   message='Password and confirmation do not match',
-                   action='manage_main')
-
-        if not roles:
-            roles = []
-        if not domains:
-            domains = []
-
-        if domains and not self.domainSpecValidate(domains):
-            return MessageDialog(
-                   title='Illegal value',
-                   message='Illegal domain specification',
-                   action='manage_main')
-        self._doChangeUser(name, password, roles, domains)
-        if REQUEST:
-            return self._mainUser(self, REQUEST)
-
-    @requestmethod('POST')
-    def _delUsers(self, names, REQUEST=None):
-        if not names:
-            return MessageDialog(
-                   title='Illegal value',
-                   message='No users specified',
-                   action='manage_main')
-        self._doDelUsers(names)
-        if REQUEST:
-            return self._mainUser(self, REQUEST)
-
-    security.declareProtected(ManageUsers, 'manage_users')
-    def manage_users(self, submit=None, REQUEST=None, RESPONSE=None):
-        """This method handles operations on users for the web based forms
-           of the ZMI. Application code (code that is outside of the forms
-           that implement the UI of a user folder) are encouraged to use
-           manage_std_addUser"""
-        if submit=='Add...':
-            return self._add_User(self, REQUEST)
-
-        if submit=='Edit':
-            try:
-                user=self.getUser(reqattr(REQUEST, 'name'))
-            except:
-                return MessageDialog(
-                    title='Illegal value',
-                    message='The specified user does not exist',
-                    action='manage_main')
-            return self._editUser(self, REQUEST, user=user, password=user.__)
-
-        if submit=='Add':
-            name = reqattr(REQUEST, 'name')
-            password = reqattr(REQUEST, 'password')
-            confirm = reqattr(REQUEST, 'confirm')
-            roles = reqattr(REQUEST, 'roles')
-            domains = reqattr(REQUEST, 'domains')
-            return self._addUser(name, password, confirm, roles,
-                                 domains, REQUEST)
-
-        if submit=='Change':
-            name = reqattr(REQUEST, 'name')
-            password = reqattr(REQUEST, 'password')
-            confirm = reqattr(REQUEST, 'confirm')
-            roles = reqattr(REQUEST, 'roles')
-            domains = reqattr(REQUEST, 'domains')
-            return self._changeUser(name, password, confirm, roles,
-                                    domains, REQUEST)
-
-        if submit=='Delete':
-            names = reqattr(REQUEST, 'names')
-            return self._delUsers(names, REQUEST)
-
-        return self._mainUser(self, REQUEST)
-
     security.declareProtected(ManageUsers, 'user_names')
     def user_names(self):
         return self.getUserNames()
 
-    def manage_beforeDelete(self, item, container):
-        if item is self:
-            try:
-                del container.__allow_groups__
-            except:
-                pass
-
-    def manage_afterAdd(self, item, container):
-        if item is self:
-            self = aq_base(self)
-            container.__allow_groups__ = self
-
     def __creatable_by_emergency_user__(self):
         return 1
 
-    def _setId(self, id):
-        if id != self.id:
-            raise MessageDialog(
-                title='Invalid Id',
-                message='Cannot change the id of a UserFolder',
-                action='./manage_main')
-
-
     # Domain authentication support. This is a good candidate to
     # become deprecated in future Zope versions.
 
@@ -640,7 +356,6 @@
 
 
 class UserFolder(BasicUserFolder):
-
     """Standard UserFolder object
 
     A UserFolder holds User objects which contain information
@@ -653,7 +368,6 @@
     meta_type = 'User Folder'
     id = 'acl_users'
     title = 'User Folder'
-    icon = 'p_/UserFolder'
 
     def __init__(self):
         self.data=PersistentMapping()
@@ -704,43 +418,4 @@
         for name in names:
             del self.data[name]
 
-    def _createInitialUser(self):
-        """
-        If there are no users or only one user in this user folder,
-        populates from the 'inituser' file in the instance home.
-        We have to do this even when there is already a user
-        just in case the initial user ignored the setup messages.
-        We don't do it for more than one user to avoid
-        abuse of this mechanism.
-        Called only by OFS.Application.initialize().
-        """
-        if len(self.data) <= 1:
-            info = readUserAccessFile('inituser')
-            if info:
-                import App.config
-                name, password, domains, remote_user_mode = info
-                self._doDelUsers(self.getUserNames())
-                self._doAddUser(name, password, ('Manager', ), domains)
-                cfg = App.config.getConfiguration()
-                try:
-                    os.remove(os.path.join(cfg.instancehome, 'inituser'))
-                except:
-                    pass
-
 InitializeClass(UserFolder)
-
-
-def manage_addUserFolder(self, dtself=None, REQUEST=None, **ignored):
-    """ """
-    f = UserFolder()
-    self = self.this()
-    try:
-        self._setObject('acl_users', f)
-    except:
-        return MessageDialog(
-            title='Item Exists',
-            message='This object already contains a User Folder',
-            action='%s/manage_main' % REQUEST['URL1'])
-    self.__allow_groups__ = f
-    if REQUEST is not None:
-        REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')

Modified: Zope/trunk/src/OFS/Application.py
===================================================================
--- Zope/trunk/src/OFS/Application.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/OFS/Application.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -27,13 +27,13 @@
 from AccessControl import ClassSecurityInfo
 from AccessControl.class_init import InitializeClass
 from AccessControl.Permission import ApplicationDefaultPermissions
-from AccessControl.User import UserFolder
 from Acquisition import aq_base
 from App.ApplicationManager import ApplicationManager
 from App.config import getConfiguration
 from App.Product import doInstall
 from DateTime import DateTime
 from HelpSys.HelpSys import HelpSys
+from OFS.userfolder import UserFolder
 from Persistence import Persistent
 from webdav.NullResource import NullResource
 from zExceptions import Redirect as RedirectException, Forbidden

Copied: Zope/trunk/src/OFS/dtml/addUser.dtml (from rev 113633, Zope/trunk/src/AccessControl/dtml/addUser.dtml)
===================================================================
--- Zope/trunk/src/OFS/dtml/addUser.dtml	                        (rev 0)
+++ Zope/trunk/src/OFS/dtml/addUser.dtml	2010-06-19 14:57:57 UTC (rev 113646)
@@ -0,0 +1,89 @@
+<dtml-var manage_page_header>
+
+<dtml-var "manage_form_title(this(), _, form_title='Add User')">
+
+<p class="form-help">
+To add a new user, enter the name <dtml-unless remote_user_mode__>
+,password, confirmation</dtml-unless> and roles for the new user and 
+click &quot;Add&quot;. <em>Domains</em> is an optional list of domains 
+from which the user is allowed to login. 
+</p>
+
+<form action="manage_users" method="post">
+<table>
+<tr>
+  <td align="left" valign="top">
+  <div class="form-label">
+  Name
+  </div>
+  </td>
+  <td align="left" valign="top">
+  <input type="text" name="name" size="30" />
+  </td>
+</tr>
+
+<dtml-if remote_user_mode__>
+<input type="hidden" name="password" value="password" />
+<input type="hidden" name="confirm"  value="password" />
+<dtml-else>
+<tr>
+  <td align="left" valign="top">
+  <div class="form-label">
+  Password
+  </div>
+  </td>
+  <td align="left" valign="top">
+  <input type="password" name="password" size="30" />
+  </td>
+</tr>
+<tr>
+  <td align="left" valign="top">
+  <div class="form-label">
+  (Confirm)
+  </div>
+  </td>
+  <td align="left" valign="top">
+  <input type="password" name="confirm" size="30" />
+  </td>
+</tr>
+</dtml-if>
+
+<tr>
+<td align="left" valign="top">
+<div class="form-optional">
+Domains
+</div>
+</td>
+<td align="left" valign="top">
+<input type="text" name="domains:tokens" size="30" value="" />
+</td>
+</tr>
+
+<tr>
+  <td align="left" valign="top">
+  <div class="form-label">
+  Roles
+  </div>
+  </td>
+  <td align="left" valign="top">
+  <div class="form-element">
+  <select name="roles:list" size="5" multiple>
+  <dtml-in valid_roles>
+  <dtml-if expr="_vars['sequence-item'] != 'Authenticated'">
+  <dtml-if expr="_vars['sequence-item'] != 'Anonymous'">
+  <dtml-if expr="_vars['sequence-item'] != 'Shared'">
+  <option value="&dtml-sequence-item;">&dtml-sequence-item;
+  </dtml-if>
+  </dtml-if>
+  </dtml-if>
+  </dtml-in valid_roles>
+  </select>
+  <br />
+  <input type="submit" name="submit" value="Add" />
+  </div>
+</td>
+</tr>
+</table>
+</form>
+
+<dtml-var manage_page_footer>

Copied: Zope/trunk/src/OFS/dtml/editUser.dtml (from rev 113633, Zope/trunk/src/AccessControl/dtml/editUser.dtml)
===================================================================
--- Zope/trunk/src/OFS/dtml/editUser.dtml	                        (rev 0)
+++ Zope/trunk/src/OFS/dtml/editUser.dtml	2010-06-19 14:57:57 UTC (rev 113646)
@@ -0,0 +1,90 @@
+<dtml-var manage_page_header>
+
+<dtml-var "manage_form_title(this(), _, form_title='Change User')">
+
+<FORM ACTION="manage_users" METHOD="POST">
+<TABLE>
+<TR>
+<TD VALIGN="TOP">
+<div class="form-label">
+Name
+</div>
+</TD>
+<TD VALIGN="TOP">
+<div class="form-text">
+<dtml-var expr="user.name" html_quote>
+</div>
+</TD>
+</TR>
+<TR><TD COLSPAN=2>&nbsp;</TD></TR>
+<dtml-if remote_user_mode__>
+  <INPUT TYPE="HIDDEN" NAME="password" value="&dtml-password;" />
+  <INPUT TYPE="HIDDEN" NAME="confirm"  value="&dtml-password;" />
+<dtml-else>
+<TR>
+<TD VALIGN="TOP">
+<div class="form-label">
+New Password
+</div>
+</TD>
+<TD VALIGN="TOP">
+<INPUT TYPE="PASSWORD" NAME="password" SIZE="30" value="password" />
+</TD>
+</TR>
+<TR>
+<TD VALIGN="TOP">
+<div class="form-label">
+(Confirm)
+</div>
+</TD>
+<TD VALIGN="TOP">
+<INPUT TYPE="PASSWORD" NAME="confirm" SIZE="30" value="pconfirm" />
+</TD>
+</TR>
+</dtml-if>
+<TR>
+<TD VALIGN="TOP">
+<div class="form-optional">
+Domains
+</div>
+</TD>
+<TD VALIGN="TOP">
+<INPUT TYPE="TEXT" NAME="domains:tokens" SIZE="30"
+  VALUE="<dtml-if expr="user.domains"><dtml-in expr="user.domains">&dtml-sequence-item; </dtml-in></dtml-if>" />
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">
+<div class="form-label">
+Roles
+</div>
+</TD>
+<TD VALIGN="TOP">
+<div class="form-element">
+<SELECT NAME="roles:list" SIZE="5" MULTIPLE>
+<dtml-in valid_roles>
+<dtml-if expr="_vars['sequence-item'] != 'Authenticated'">
+<dtml-if expr="_vars['sequence-item'] != 'Anonymous'">
+<dtml-if expr="_vars['sequence-item'] != 'Shared'">
+<dtml-if expr="_vars['sequence-item'] in user.roles">
+<OPTION VALUE="&dtml-sequence-item;" selected>&dtml-sequence-item;
+<dtml-else>
+<OPTION VALUE="&dtml-sequence-item;">&dtml-sequence-item;
+</dtml-if>
+</dtml-if>
+</dtml-if>
+</dtml-if>
+</dtml-in valid_roles>
+</SELECT>
+
+<INPUT TYPE="HIDDEN" NAME="name" VALUE="<dtml-var expr="user.name" html_quote>" />
+<br /><br />
+<INPUT class="form-element" TYPE="SUBMIT" NAME="submit" VALUE="Change" />
+</div>
+</TD>
+</TR>
+</TABLE>
+</FORM>
+
+<dtml-var manage_page_footer>

Copied: Zope/trunk/src/OFS/dtml/mainUser.dtml (from rev 113633, Zope/trunk/src/AccessControl/dtml/mainUser.dtml)
===================================================================
--- Zope/trunk/src/OFS/dtml/mainUser.dtml	                        (rev 0)
+++ Zope/trunk/src/OFS/dtml/mainUser.dtml	2010-06-19 14:57:57 UTC (rev 113646)
@@ -0,0 +1,55 @@
+<dtml-var manage_page_header>
+<dtml-var manage_tabs>
+
+<form action="manage_users" method="post">
+<dtml-if user_names>
+<p class="form-help">
+The following users have been defined. Click on the name of a 
+user to edit that user.
+</p>
+
+<table cellspacing="0" cellpadding="2" border="0">
+<dtml-in user_names>
+<dtml-if sequence-odd>
+<tr class="row-normal">
+<dtml-else>
+<tr class="row-hilite">
+</dtml-if>
+  <td align="left" valign="top">
+  <input type="checkbox" name="names:list" value="&dtml-sequence-item;" />
+  </td>
+  <td align="left" valign="top">
+  <div class="list-item">
+  <a href="manage_users?name=&dtml.url_quote-sequence-item;&submit=Edit"><img src="&dtml-BASEPATH1;/p_/User_icon"
+   alt="" border="0" /></a>
+  <a href="manage_users?name=&dtml.url_quote-sequence-item;&submit=Edit">&dtml-sequence-item;</a>
+  </div>
+  </td>
+</tr>
+</dtml-in user_names>
+<tr>
+  <td align="left" valign="top">&nbsp;
+  </td>
+  <td align="left" valign="top">
+  <div class="form-element">
+  <input class="form-element" type="submit" name="submit" value="Add..." />
+  <input class="form-element" type="submit" name="submit" value="Delete" />
+  </div>
+  </td>
+</tr>
+</table>
+<dtml-else user_names>
+<p class="std-text">
+There are no users defined.
+</p>
+
+<p>
+<div class="form-element">
+<input class="form-element" type="submit" name="submit" value="Add..." />
+</div>
+</p>
+</dtml-if user_names>
+</form>
+
+<dtml-var manage_page_footer>
+

Copied: Zope/trunk/src/OFS/dtml/userFolderProps.dtml (from rev 113633, Zope/trunk/src/AccessControl/dtml/userFolderProps.dtml)
===================================================================
--- Zope/trunk/src/OFS/dtml/userFolderProps.dtml	                        (rev 0)
+++ Zope/trunk/src/OFS/dtml/userFolderProps.dtml	2010-06-19 14:57:57 UTC (rev 113646)
@@ -0,0 +1,40 @@
+<dtml-var manage_page_header>
+<dtml-var manage_tabs>
+
+<form action="manage_setUserFolderProperties" method="post">
+
+<table cellspacing="0" cellpadding="2" border="0">
+
+<tr>
+  <td align="left" valign="center" class="form-label">
+   Encrypt user passwords
+  </td>
+  <td align="left" valign="center" class="form-element">
+   <dtml-let checked="encrypt_passwords and 'checked' or ' '">
+   <input type="checkbox" name="encrypt_passwords" &dtml-checked;>
+   &nbsp; &nbsp;
+   <input type="submit" name="update_passwords" value="Update existing passwords">
+   </dtml-let>
+  </td>
+</tr>
+<tr>
+ <td align="left" valign="center" class="form-label">
+  Role assignment presents search dialog when more users than N (-1 is always, 0 is never).
+ </td>
+ <td align="left" valign="center" class="form-element">
+ <input type=text name="maxlistusers" value="&dtml.missing-maxlistusers;" size=3>
+ </td>
+</tr>
+
+</table>
+
+<p>
+<div class="form-element">
+<input class="form-element" type="submit" name="submit" value="Save changes" />
+</div>
+</p>
+
+</form>
+
+<dtml-var manage_page_footer>
+

Modified: Zope/trunk/src/OFS/role.py
===================================================================
--- Zope/trunk/src/OFS/role.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/OFS/role.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -10,8 +10,9 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-"""Access control support
+"""Role manager
 """
+
 from cgi import escape
 
 from App.Dialogs import MessageDialog

Deleted: Zope/trunk/src/OFS/tests/testUserFolder.py
===================================================================
--- Zope/trunk/src/OFS/tests/testUserFolder.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/OFS/tests/testUserFolder.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -1,289 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Foundation and Contributors.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (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.
-#
-##############################################################################
-""" Unit tests for AccessControl.User
-"""
-import unittest
-
-# TODO class Test_readUserAccessFile(unittest.TestCase)
-
-
-# TODO class BasicUserFoldertests(unittest.TestCase)
-
-
-class UserFolderTests(unittest.TestCase):
-
-    def setUp(self):
-        import transaction
-        transaction.begin()
-
-    def tearDown(self):
-        import transaction
-        from AccessControl.SecurityManagement import noSecurityManager
-        noSecurityManager()
-        transaction.abort()
-
-    def _getTargetClass(self):
-        from AccessControl.User import UserFolder
-        return UserFolder
-
-    def _makeOne(self, app=None):
-        if app is None:
-            app = self._makeApp()
-        uf = self._getTargetClass()().__of__(app)
-        uf._doAddUser('user1', 'secret', ['role1'], [])
-        return uf
-
-    def _makeApp(self):
-        from Testing.makerequest import makerequest
-        from Testing.ZopeTestCase import ZopeLite
-        app = makerequest(ZopeLite.app())
-        # Set up a user and role
-        app._addRole('role1')
-        app.manage_role('role1', ['View'])
-        # Set up a published object accessible to user
-        app.addDTMLMethod('doc', file='')
-        app.doc.manage_permission('View', ['role1'], acquire=0)
-        # Rig the REQUEST so it looks like we traversed to doc
-        app.REQUEST.set('PUBLISHED', app.doc)
-        app.REQUEST.set('PARENTS', [app])
-        app.REQUEST.steps = ['doc']
-        return app
-
-    def _makeBasicAuthToken(self, creds='user1:secret'):
-        import base64
-        return 'Basic %s' % base64.encodestring(creds)
-
-    def _login(self, uf, name):
-        from AccessControl.SecurityManagement import newSecurityManager
-        user = uf.getUserById(name)
-        user = user.__of__(uf)
-        newSecurityManager(None, user)
-
-    def test_class_conforms_to_IStandardUserFolder(self):
-        from AccessControl.interfaces import IStandardUserFolder
-        from zope.interface.verify import verifyClass
-        verifyClass(IStandardUserFolder, self._getTargetClass())
-
-    def testGetUser(self):
-        uf = self._makeOne()
-        self.failIfEqual(uf.getUser('user1'), None)
-
-    def testGetBadUser(self):
-        uf = self._makeOne()
-        self.assertEqual(uf.getUser('user2'), None)
-
-    def testGetUserById(self):
-        uf = self._makeOne()
-        self.failIfEqual(uf.getUserById('user1'), None)
-
-    def testGetBadUserById(self):
-        uf = self._makeOne()
-        self.assertEqual(uf.getUserById('user2'), None)
-
-    def testGetUsers(self):
-        uf = self._makeOne()
-        users = uf.getUsers()
-        self.failUnless(users)
-        self.assertEqual(users[0].getUserName(), 'user1')
-
-    def testGetUserNames(self):
-        uf = self._makeOne()
-        names = uf.getUserNames()
-        self.failUnless(names)
-        self.assertEqual(names[0], 'user1')
-
-    def testIdentify(self):
-        uf = self._makeOne()
-        name, password = uf.identify(self._makeBasicAuthToken())
-        self.assertEqual(name, 'user1')
-        self.assertEqual(password, 'secret')
-
-    def testGetRoles(self):
-        uf = self._makeOne()
-        user = uf.getUser('user1')
-        self.failUnless('role1' in user.getRoles())
-
-    def testGetRolesInContext(self):
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        user = uf.getUser('user1')
-        app.manage_addLocalRoles('user1', ['Owner'])
-        roles = user.getRolesInContext(app)
-        self.failUnless('role1' in roles)
-        self.failUnless('Owner' in roles)
-
-    def testHasRole(self):
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        user = uf.getUser('user1')
-        self.failUnless(user.has_role('role1', app))
-
-    def testHasLocalRole(self):
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        user = uf.getUser('user1')
-        app.manage_addLocalRoles('user1', ['Owner'])
-        self.failUnless(user.has_role('Owner', app))
-
-    def testHasPermission(self):
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        user = uf.getUser('user1')
-        self.failUnless(user.has_permission('View', app))
-        app.manage_role('role1', ['Add Folders'])
-        self.failUnless(user.has_permission('Add Folders', app))
-
-    def testHasLocalRolePermission(self):
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        user = uf.getUser('user1')
-        app.manage_role('Owner', ['Add Folders'])
-        app.manage_addLocalRoles('user1', ['Owner'])
-        self.failUnless(user.has_permission('Add Folders', app))
-        
-    def testAuthenticate(self):
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        user = uf.getUser('user1')
-        self.failUnless(user.authenticate('secret', app.REQUEST))
-
-    def testValidate(self):
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        user = uf.validate(app.REQUEST, self._makeBasicAuthToken(),
-                           ['role1'])
-        self.failIfEqual(user, None)
-        self.assertEqual(user.getUserName(), 'user1')
-
-    def testNotValidateWithoutAuth(self):
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        user = uf.validate(app.REQUEST, '', ['role1'])
-        self.assertEqual(user, None)
-
-    def testValidateWithoutRoles(self):
-        # Note - calling uf.validate without specifying roles will cause
-        # the security machinery to determine the needed roles by looking
-        # at the object itself (or its container). I'm putting this note
-        # in to clarify because the original test expected failure but it
-        # really should have expected success, since the user and the
-        # object being checked both have the role 'role1', even though no
-        # roles are passed explicitly to the userfolder validate method.
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        user = uf.validate(app.REQUEST, self._makeBasicAuthToken())
-        self.assertEqual(user.getUserName(), 'user1')
-
-    def testNotValidateWithEmptyRoles(self):
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        user = uf.validate(app.REQUEST, self._makeBasicAuthToken(), [])
-        self.assertEqual(user, None)
-
-    def testNotValidateWithWrongRoles(self):
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        user = uf.validate(app.REQUEST, self._makeBasicAuthToken(),
-                           ['Manager'])
-        self.assertEqual(user, None)
-
-    def testAllowAccessToUser(self):
-        app = self._makeApp()
-        uf = self._makeOne(app)
-        self._login(uf, 'user1')
-        app.restrictedTraverse('doc')
-
-    def testDenyAccessToAnonymous(self):
-        from AccessControl import Unauthorized
-        app = self._makeApp()
-        self.assertRaises(Unauthorized, app.restrictedTraverse, 'doc')
-
-    def testMaxListUsers(self):
-        # create a folder-ish thing which contains a roleManager,
-        # then put an acl_users object into the folde-ish thing
-        from AccessControl.User import BasicUserFolder
-
-        class Folderish(BasicUserFolder):
-            def __init__(self, size, count):
-                self.maxlistusers = size
-                self.users = []
-                self.acl_users = self
-                self.__allow_groups__ = self
-                for i in xrange(count):
-                    self.users.append("Nobody")
-
-            def getUsers(self):
-                return self.users
-
-            def user_names(self):
-                return self.getUsers()
-
-
-        tinyFolderOver = Folderish(15, 20)
-        tinyFolderUnder = Folderish(15, 10)
-
-        assert tinyFolderOver.maxlistusers == 15
-        assert tinyFolderUnder.maxlistusers == 15
-        assert len(tinyFolderOver.user_names()) == 20
-        assert len(tinyFolderUnder.user_names()) == 10
-
-        try:
-            list = tinyFolderOver.get_valid_userids()
-            assert 0, "Did not raise overflow error"
-        except OverflowError:
-            pass
-
-        try:
-            list = tinyFolderUnder.get_valid_userids()
-            pass
-        except OverflowError:
-            assert 0, "Raised overflow error erroneously"
-
-    def test__doAddUser_with_not_yet_encrypted_passwords(self):
-        # See collector #1869 && #1926
-        from AccessControl.AuthEncoding import pw_validate
-
-        USER_ID = 'not_yet_encrypted'
-        PASSWORD = 'password'
-
-        uf = self._makeOne()
-        uf.encrypt_passwords = True
-        self.failIf(uf._isPasswordEncrypted(PASSWORD))
-
-        uf._doAddUser(USER_ID, PASSWORD, [], [])
-        user = uf.getUserById(USER_ID)
-        self.failUnless(uf._isPasswordEncrypted(user.__))
-        self.failUnless(pw_validate(user.__, PASSWORD))
-
-    def test__doAddUser_with_preencrypted_passwords(self):
-        # See collector #1869 && #1926
-        from AccessControl.AuthEncoding import pw_validate
-
-        USER_ID = 'already_encrypted'
-        PASSWORD = 'password'
-
-        uf = self._makeOne()
-        uf.encrypt_passwords = True
-        ENCRYPTED = uf._encryptPassword(PASSWORD)
-
-        uf._doAddUser(USER_ID, ENCRYPTED, [], [])
-        user = uf.getUserById(USER_ID)
-        self.assertEqual(user.__, ENCRYPTED)
-        self.failUnless(uf._isPasswordEncrypted(user.__))
-        self.failUnless(pw_validate(user.__, PASSWORD))
-
-
-def test_suite():
-    suite = unittest.TestSuite()
-    suite.addTest(unittest.makeSuite(UserFolderTests))
-    return suite

Copied: Zope/trunk/src/OFS/tests/test_userfolder.py (from rev 113633, Zope/trunk/src/OFS/tests/testUserFolder.py)
===================================================================
--- Zope/trunk/src/OFS/tests/test_userfolder.py	                        (rev 0)
+++ Zope/trunk/src/OFS/tests/test_userfolder.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -0,0 +1,176 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+""" Unit tests for OFS.userfolder
+"""
+import unittest
+
+# TODO class Test_readUserAccessFile(unittest.TestCase)
+
+
+# TODO class BasicUserFoldertests(unittest.TestCase)
+
+
+class UserFolderTests(unittest.TestCase):
+
+    def setUp(self):
+        import transaction
+        transaction.begin()
+
+    def tearDown(self):
+        import transaction
+        from AccessControl.SecurityManagement import noSecurityManager
+        noSecurityManager()
+        transaction.abort()
+
+    def _getTargetClass(self):
+        from OFS.userfolder import UserFolder
+        return UserFolder
+
+    def _makeOne(self, app=None):
+        if app is None:
+            app = self._makeApp()
+        uf = self._getTargetClass()().__of__(app)
+        uf._doAddUser('user1', 'secret', ['role1'], [])
+        return uf
+
+    def _makeApp(self):
+        from Testing.makerequest import makerequest
+        from Testing.ZopeTestCase import ZopeLite
+        app = makerequest(ZopeLite.app())
+        # Set up a user and role
+        app._addRole('role1')
+        app.manage_role('role1', ['View'])
+        # Set up a published object accessible to user
+        app.addDTMLMethod('doc', file='')
+        app.doc.manage_permission('View', ['role1'], acquire=0)
+        # Rig the REQUEST so it looks like we traversed to doc
+        app.REQUEST.set('PUBLISHED', app.doc)
+        app.REQUEST.set('PARENTS', [app])
+        app.REQUEST.steps = ['doc']
+        return app
+
+    def _makeBasicAuthToken(self, creds='user1:secret'):
+        import base64
+        return 'Basic %s' % base64.encodestring(creds)
+
+    def _login(self, uf, name):
+        from AccessControl.SecurityManagement import newSecurityManager
+        user = uf.getUserById(name)
+        user = user.__of__(uf)
+        newSecurityManager(None, user)
+
+    def test_class_conforms_to_IStandardUserFolder(self):
+        from AccessControl.interfaces import IStandardUserFolder
+        from zope.interface.verify import verifyClass
+        verifyClass(IStandardUserFolder, self._getTargetClass())
+
+    def testGetRolesInContext(self):
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        user = uf.getUser('user1')
+        app.manage_addLocalRoles('user1', ['Owner'])
+        roles = user.getRolesInContext(app)
+        self.failUnless('role1' in roles)
+        self.failUnless('Owner' in roles)
+
+    def testHasRole(self):
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        user = uf.getUser('user1')
+        self.failUnless(user.has_role('role1', app))
+
+    def testHasLocalRole(self):
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        user = uf.getUser('user1')
+        app.manage_addLocalRoles('user1', ['Owner'])
+        self.failUnless(user.has_role('Owner', app))
+
+    def testHasPermission(self):
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        user = uf.getUser('user1')
+        self.failUnless(user.has_permission('View', app))
+        app.manage_role('role1', ['Add Folders'])
+        self.failUnless(user.has_permission('Add Folders', app))
+
+    def testHasLocalRolePermission(self):
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        user = uf.getUser('user1')
+        app.manage_role('Owner', ['Add Folders'])
+        app.manage_addLocalRoles('user1', ['Owner'])
+        self.failUnless(user.has_permission('Add Folders', app))
+        
+    def testAuthenticate(self):
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        user = uf.getUser('user1')
+        self.failUnless(user.authenticate('secret', app.REQUEST))
+
+    def testValidate(self):
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        user = uf.validate(app.REQUEST, self._makeBasicAuthToken(),
+                           ['role1'])
+        self.failIfEqual(user, None)
+        self.assertEqual(user.getUserName(), 'user1')
+
+    def testNotValidateWithoutAuth(self):
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        user = uf.validate(app.REQUEST, '', ['role1'])
+        self.assertEqual(user, None)
+
+    def testValidateWithoutRoles(self):
+        # Note - calling uf.validate without specifying roles will cause
+        # the security machinery to determine the needed roles by looking
+        # at the object itself (or its container). I'm putting this note
+        # in to clarify because the original test expected failure but it
+        # really should have expected success, since the user and the
+        # object being checked both have the role 'role1', even though no
+        # roles are passed explicitly to the userfolder validate method.
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        user = uf.validate(app.REQUEST, self._makeBasicAuthToken())
+        self.assertEqual(user.getUserName(), 'user1')
+
+    def testNotValidateWithEmptyRoles(self):
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        user = uf.validate(app.REQUEST, self._makeBasicAuthToken(), [])
+        self.assertEqual(user, None)
+
+    def testNotValidateWithWrongRoles(self):
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        user = uf.validate(app.REQUEST, self._makeBasicAuthToken(),
+                           ['Manager'])
+        self.assertEqual(user, None)
+
+    def testAllowAccessToUser(self):
+        app = self._makeApp()
+        uf = self._makeOne(app)
+        self._login(uf, 'user1')
+        app.restrictedTraverse('doc')
+
+    def testDenyAccessToAnonymous(self):
+        from AccessControl import Unauthorized
+        app = self._makeApp()
+        self.assertRaises(Unauthorized, app.restrictedTraverse, 'doc')
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(UserFolderTests))
+    return suite

Copied: Zope/trunk/src/OFS/userfolder.py (from rev 113645, Zope/trunk/src/AccessControl/userfolder.py)
===================================================================
--- Zope/trunk/src/OFS/userfolder.py	                        (rev 0)
+++ Zope/trunk/src/OFS/userfolder.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -0,0 +1,346 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+"""User folders
+"""
+
+import os
+
+from Acquisition import aq_base
+
+from App.Management import Navigation
+from App.Management import Tabs
+from App.special_dtml import DTMLFile
+from App.Dialogs import MessageDialog
+from OFS.role import RoleManager
+from OFS.SimpleItem import Item
+
+from AccessControl import ClassSecurityInfo
+from AccessControl.class_init import InitializeClass
+from AccessControl.Permissions import manage_users as ManageUsers
+from AccessControl.requestmethod import requestmethod
+from AccessControl.rolemanager import DEFAULTMAXLISTUSERS
+from AccessControl import userfolder as accesscontrol_userfolder
+from AccessControl.users import readUserAccessFile
+from AccessControl.users import _remote_user_mode
+from AccessControl.users import emergency_user
+from AccessControl.users import reqattr
+
+
+class BasicUserFolder(Navigation, Tabs, Item, RoleManager,
+                      accesscontrol_userfolder.BasicUserFolder):
+    """Base class for UserFolder-like objects"""
+
+    security = ClassSecurityInfo()
+
+    # Note: use of the '_super' name is deprecated.
+    _super = emergency_user
+
+    manage_options=(
+        (
+        {'label': 'Contents', 'action': 'manage_main'},
+        {'label': 'Properties', 'action': 'manage_userFolderProperties'},
+        )
+        +RoleManager.manage_options
+        +Item.manage_options
+        )
+
+    security.declareProtected(ManageUsers, 'userFolderAddUser')
+    @requestmethod('POST')
+    def userFolderAddUser(self, name, password, roles, domains,
+                          REQUEST=None, **kw):
+        """API method for creating a new user object. Note that not all
+           user folder implementations support dynamic creation of user
+           objects."""
+        if hasattr(self, '_doAddUser'):
+            return self._doAddUser(name, password, roles, domains, **kw)
+        raise NotImplementedError
+
+    security.declareProtected(ManageUsers, 'userFolderEditUser')
+    @requestmethod('POST')
+    def userFolderEditUser(self, name, password, roles, domains,
+                           REQUEST=None, **kw):
+        """API method for changing user object attributes. Note that not
+           all user folder implementations support changing of user object
+           attributes."""
+        if hasattr(self, '_doChangeUser'):
+            return self._doChangeUser(name, password, roles, domains, **kw)
+        raise NotImplementedError
+
+    security.declareProtected(ManageUsers, 'userFolderDelUsers')
+    @requestmethod('POST')
+    def userFolderDelUsers(self, names, REQUEST=None):
+        """API method for deleting one or more user objects. Note that not
+           all user folder implementations support deletion of user objects."""
+        if hasattr(self, '_doDelUsers'):
+            return self._doDelUsers(names)
+        raise NotImplementedError
+
+    _mainUser=DTMLFile('dtml/mainUser', globals())
+    _add_User=DTMLFile('dtml/addUser', globals(),
+                       remote_user_mode__=_remote_user_mode)
+    _editUser=DTMLFile('dtml/editUser', globals(),
+                       remote_user_mode__=_remote_user_mode)
+    manage=manage_main=_mainUser
+    manage_main._setName('manage_main')
+
+    _userFolderProperties = DTMLFile('dtml/userFolderProps', globals())
+
+    def manage_userFolderProperties(self, REQUEST=None,
+                                    manage_tabs_message=None):
+        """
+        """
+        return self._userFolderProperties(
+            self, REQUEST, manage_tabs_message=manage_tabs_message,
+            management_view='Properties')
+
+    @requestmethod('POST')
+    def manage_setUserFolderProperties(self, encrypt_passwords=0,
+                                       update_passwords=0,
+                                       maxlistusers=DEFAULTMAXLISTUSERS,
+                                       REQUEST=None):
+        """
+        Sets the properties of the user folder.
+        """
+        self.encrypt_passwords = not not encrypt_passwords
+        try:
+            self.maxlistusers = int(maxlistusers)
+        except ValueError:
+            self.maxlistusers = DEFAULTMAXLISTUSERS
+        if encrypt_passwords and update_passwords:
+            changed = 0
+            for u in self.getUsers():
+                pw = u._getPassword()
+                if not self._isPasswordEncrypted(pw):
+                    pw = self._encryptPassword(pw)
+                    self._doChangeUser(u.getUserName(), pw, u.getRoles(),
+                                       u.getDomains())
+                    changed = changed + 1
+            if REQUEST is not None:
+                if not changed:
+                    msg = 'All passwords already encrypted.'
+                else:
+                    msg = 'Encrypted %d password(s).' % changed
+                return self.manage_userFolderProperties(
+                    REQUEST, manage_tabs_message=msg)
+            else:
+                return changed
+        else:
+            if REQUEST is not None:
+                return self.manage_userFolderProperties(
+                    REQUEST, manage_tabs_message='Saved changes.')
+
+    @requestmethod('POST')
+    def _addUser(self, name, password, confirm, roles, domains, REQUEST=None):
+        if not name:
+            return MessageDialog(
+                   title='Illegal value',
+                   message='A username must be specified',
+                   action='manage_main')
+        if not password or not confirm:
+            if not domains:
+                return MessageDialog(
+                   title='Illegal value',
+                   message='Password and confirmation must be specified',
+                   action='manage_main')
+        if self.getUser(name) or (self._emergency_user and
+                                  name == self._emergency_user.getUserName()):
+            return MessageDialog(
+                   title='Illegal value',
+                   message='A user with the specified name already exists',
+                   action='manage_main')
+        if (password or confirm) and (password != confirm):
+            return MessageDialog(
+                   title='Illegal value',
+                   message='Password and confirmation do not match',
+                   action='manage_main')
+
+        if not roles:
+            roles = []
+        if not domains:
+            domains = []
+
+        if domains and not self.domainSpecValidate(domains):
+            return MessageDialog(
+                   title='Illegal value',
+                   message='Illegal domain specification',
+                   action='manage_main')
+        self._doAddUser(name, password, roles, domains)
+        if REQUEST:
+            return self._mainUser(self, REQUEST)
+
+    @requestmethod('POST')
+    def _changeUser(self, name, password, confirm, roles, domains,
+                    REQUEST=None):
+        if password == 'password' and confirm == 'pconfirm':
+            # Protocol for editUser.dtml to indicate unchanged password
+            password = confirm = None
+        if not name:
+            return MessageDialog(
+                   title='Illegal value',
+                   message='A username must be specified',
+                   action='manage_main')
+        if password == confirm == '':
+            if not domains:
+                return MessageDialog(
+                   title='Illegal value',
+                   message='Password and confirmation must be specified',
+                   action='manage_main')
+        if not self.getUser(name):
+            return MessageDialog(
+                   title='Illegal value',
+                   message='Unknown user',
+                   action='manage_main')
+        if (password or confirm) and (password != confirm):
+            return MessageDialog(
+                   title='Illegal value',
+                   message='Password and confirmation do not match',
+                   action='manage_main')
+
+        if not roles:
+            roles = []
+        if not domains:
+            domains = []
+
+        if domains and not self.domainSpecValidate(domains):
+            return MessageDialog(
+                   title='Illegal value',
+                   message='Illegal domain specification',
+                   action='manage_main')
+        self._doChangeUser(name, password, roles, domains)
+        if REQUEST:
+            return self._mainUser(self, REQUEST)
+
+    @requestmethod('POST')
+    def _delUsers(self, names, REQUEST=None):
+        if not names:
+            return MessageDialog(
+                   title='Illegal value',
+                   message='No users specified',
+                   action='manage_main')
+        self._doDelUsers(names)
+        if REQUEST:
+            return self._mainUser(self, REQUEST)
+
+    security.declareProtected(ManageUsers, 'manage_users')
+    def manage_users(self, submit=None, REQUEST=None, RESPONSE=None):
+        """This method handles operations on users for the web based forms
+           of the ZMI. Application code (code that is outside of the forms
+           that implement the UI of a user folder) are encouraged to use
+           manage_std_addUser"""
+        if submit=='Add...':
+            return self._add_User(self, REQUEST)
+
+        if submit=='Edit':
+            try:
+                user=self.getUser(reqattr(REQUEST, 'name'))
+            except:
+                return MessageDialog(
+                    title='Illegal value',
+                    message='The specified user does not exist',
+                    action='manage_main')
+            return self._editUser(self, REQUEST, user=user, password=user.__)
+
+        if submit=='Add':
+            name = reqattr(REQUEST, 'name')
+            password = reqattr(REQUEST, 'password')
+            confirm = reqattr(REQUEST, 'confirm')
+            roles = reqattr(REQUEST, 'roles')
+            domains = reqattr(REQUEST, 'domains')
+            return self._addUser(name, password, confirm, roles,
+                                 domains, REQUEST)
+
+        if submit=='Change':
+            name = reqattr(REQUEST, 'name')
+            password = reqattr(REQUEST, 'password')
+            confirm = reqattr(REQUEST, 'confirm')
+            roles = reqattr(REQUEST, 'roles')
+            domains = reqattr(REQUEST, 'domains')
+            return self._changeUser(name, password, confirm, roles,
+                                    domains, REQUEST)
+
+        if submit=='Delete':
+            names = reqattr(REQUEST, 'names')
+            return self._delUsers(names, REQUEST)
+
+        return self._mainUser(self, REQUEST)
+
+    def manage_beforeDelete(self, item, container):
+        if item is self:
+            try:
+                del container.__allow_groups__
+            except:
+                pass
+
+    def manage_afterAdd(self, item, container):
+        if item is self:
+            self = aq_base(self)
+            container.__allow_groups__ = self
+
+    def _setId(self, id):
+        if id != self.id:
+            raise MessageDialog(
+                title='Invalid Id',
+                message='Cannot change the id of a UserFolder',
+                action='./manage_main')
+
+
+class UserFolder(accesscontrol_userfolder.UserFolder, BasicUserFolder):
+    """Standard UserFolder object
+
+    A UserFolder holds User objects which contain information
+    about users including name, password domain, and roles.
+    UserFolders function chiefly to control access by authenticating
+    users and binding them to a collection of roles."""
+
+    icon = 'p_/UserFolder'
+
+    def _createInitialUser(self):
+        """
+        If there are no users or only one user in this user folder,
+        populates from the 'inituser' file in the instance home.
+        We have to do this even when there is already a user
+        just in case the initial user ignored the setup messages.
+        We don't do it for more than one user to avoid
+        abuse of this mechanism.
+        Called only by OFS.Application.initialize().
+        """
+        if len(self.data) <= 1:
+            info = readUserAccessFile('inituser')
+            if info:
+                import App.config
+                name, password, domains, remote_user_mode = info
+                self._doDelUsers(self.getUserNames())
+                self._doAddUser(name, password, ('Manager', ), domains)
+                cfg = App.config.getConfiguration()
+                try:
+                    os.remove(os.path.join(cfg.instancehome, 'inituser'))
+                except:
+                    pass
+
+InitializeClass(UserFolder)
+
+
+def manage_addUserFolder(self, dtself=None, REQUEST=None, **ignored):
+    """ """
+    f = UserFolder()
+    self = self.this()
+    try:
+        self._setObject('acl_users', f)
+    except:
+        return MessageDialog(
+            title='Item Exists',
+            message='This object already contains a User Folder',
+            action='%s/manage_main' % REQUEST['URL1'])
+    self.__allow_groups__ = f
+    if REQUEST is not None:
+        REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')

Modified: Zope/trunk/src/Products/OFSP/__init__.py
===================================================================
--- Zope/trunk/src/Products/OFSP/__init__.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/Products/OFSP/__init__.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -14,7 +14,7 @@
 $Id$'''
 __version__='$Revision: 1.38 $'[11:-2]
 
-import OFS.Image, OFS.Folder, AccessControl.User
+import OFS.Image, OFS.Folder, OFS.userfolder
 import OFS.DTMLMethod, OFS.DTMLDocument, OFS.PropertySheets
 import OFS.OrderedFolder
 
@@ -79,10 +79,10 @@
         )
 
     context.registerClass(
-        AccessControl.User.UserFolder,
-        constructors=(AccessControl.User.manage_addUserFolder,),
+        OFS.userfolder.UserFolder,
+        constructors=(OFS.userfolder.manage_addUserFolder,),
         icon='images/UserFolder_icon.gif',
-        legacy=(AccessControl.User.manage_addUserFolder,),
+        legacy=(OFS.userfolder.manage_addUserFolder,),
         )
 
     context.registerHelp()

Modified: Zope/trunk/src/Testing/ZopeTestCase/ZopeTestCase.py
===================================================================
--- Zope/trunk/src/Testing/ZopeTestCase/ZopeTestCase.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/Testing/ZopeTestCase/ZopeTestCase.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -71,7 +71,7 @@
 
     def _setupUserFolder(self):
         '''Creates the user folder.'''
-        from AccessControl.User import manage_addUserFolder
+        from OFS.userfolder import manage_addUserFolder
         manage_addUserFolder(self.folder)
 
     def _setupUser(self):

Modified: Zope/trunk/src/Testing/ZopeTestCase/testPortalTestCase.py
===================================================================
--- Zope/trunk/src/Testing/ZopeTestCase/testPortalTestCase.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/Testing/ZopeTestCase/testPortalTestCase.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -406,7 +406,7 @@
         self.assertEqual(lhs, rhs)
 
 
-from AccessControl.User import UserFolder
+from OFS.userfolder import UserFolder
 
 class WrappingUserFolder(UserFolder):
     '''User folder returning wrapped user objects'''

Modified: Zope/trunk/src/Testing/ZopeTestCase/testZopeTestCase.py
===================================================================
--- Zope/trunk/src/Testing/ZopeTestCase/testZopeTestCase.py	2010-06-19 13:59:31 UTC (rev 113645)
+++ Zope/trunk/src/Testing/ZopeTestCase/testZopeTestCase.py	2010-06-19 14:57:57 UTC (rev 113646)
@@ -349,7 +349,7 @@
         self.assertEqual(lhs, rhs)
 
 
-from AccessControl.User import UserFolder
+from OFS.userfolder import UserFolder
 from Acquisition import aq_inner, aq_parent, aq_chain
 
 class WrappingUserFolder(UserFolder):



More information about the Zope-Checkins mailing list