[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 "Add". <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> </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">
+ </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;>
+
+ <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