Commit 7c0bc437 authored by Alexandre Boeglin's avatar Alexandre Boeglin

Modified the security management : it still depends on category values, but

only the part that is site specific has been taken out.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@3735 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 65d07f0d
......@@ -21,7 +21,7 @@
##############################################################################
from Globals import InitializeClass, DTMLFile
from AccessControl import ClassSecurityInfo
from AccessControl import ClassSecurityInfo, getSecurityManager
from Acquisition import aq_base, aq_inner, aq_parent
import Products.CMFCore.TypesTool
......@@ -39,7 +39,7 @@ from RoleInformation import ori
from zLOG import LOG
ERP5TYPE_ROLE_INIT_SCRIPT = 'ERP5Type_initLocalRoleMapping'
ERP5TYPE_SECURITY_GROUP_ID_GENERATION_SCRIPT = 'ERP5TypeSecurity_asGroupId'
class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
"""
......@@ -106,7 +106,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
hidden_content_type_list = ()
filter_actions = 0
allowed_action_list = []
#
# Acquisition editing interface
#
......@@ -119,7 +119,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
"""
self.setMethodAliases({})
return 1
security.declarePublic('hideFromAddMenu')
def hidenFromAddMenu(self):
"""
......@@ -140,24 +140,18 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
"""
ob = FactoryTypeInformation.constructInstance(self, container, id, *args, **kw)
# Only try to find the local role init script
# if some roles are defined
# Only try to assign roles to secutiry groups if some roles are defined
# This is an optimisation to prevent defining local roles on subobjects
# which acquire their security definition from their parent
# The downside of this optimisation is that it is not possible to
# The downside of this optimisation is that it is not possible to
# set a local role definition if the local role list is empty
if len(self._roles):
init_role_script = getattr(ob, ERP5TYPE_ROLE_INIT_SCRIPT, None)
if init_role_script is not None:
# Retrieve applicable roles
role_mapping = self.getFilteredRoleListFor(object = self) # kw provided in order to take any appropriate action
# Call the local role init script
init_role_script(role_mapping = role_mapping, **kw)
self.assignRoleToSecurityGroup(ob)
if self.init_script:
# Acquire the init script in the context of this object
init_script = getattr(ob, self.init_script)
init_script(*args, **kw)
# Acquire the init script in the context of this object
init_script = getattr(ob, self.init_script)
init_script(*args, **kw)
return ob
......@@ -193,6 +187,79 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
result.sort()
return result
security.declareProtected(ERP5Permissions.ModifyPortalContent, 'assignRoleToSecurityGroup')
def assignRoleToSecurityGroup(self, object):
"""
Assign Local Roles to Groups on object, based on Portal Type Role Definitions
"""
user_name = getSecurityManager().getUser().getUserName()
# First of all, check that NuxUserGroups is here. Otherwise, it's not possible to give Roles to Groups
try:
import Products.NuxUserGroups
except ImportError:
raise RuntimeError, 'Product "NuxUserGroups" was not found on your setup. '\
'Please install it to benefit from group-based security'
# Retrieve applicable roles
role_mapping = self.getFilteredRoleListFor(object = self) # kw provided in order to take any appropriate action
role_category_list = {}
for role, definition_list in role_mapping.items():
if not role_category_list.has_key(role):
role_category_list[role] = []
# For each role definition, we look for the base_category_script
# and try to use it to retrieve the values for the base_category list
for definition in definition_list:
base_category_script = getattr(object, definition['base_category_script'], None)
if base_category_script is not None:
# call the script, which should return either a dict or a list of dicts
category_result = base_category_script(definition['base_category'], user_name, object, object.getPortalType())
# we also need to store the user specified order of categories, as dict are not ordered
category_order_list = []
category_order_list.extend(definition['base_category'])
for c in definition['category']:
bc = c.split('/')[0]
if bc not in category_order_list:
category_order_list.append(bc)
# add the result to role_category_list
if type(category_result) is type({}):
category_result = [category_result]
for category_dict in category_result:
category_value_dict = {'category_order':category_order_list}
category_value_dict.update(category_dict)
for c in definition['category']:
bc, value = c.split('/', 1)
category_value_dict[bc] = value
role_category_list[role].append(category_value_dict)
# Generate security group ids from category_value_dicts
role_group_id_dict = {}
group_id_generator = getattr(object, ERP5TYPE_SECURITY_GROUP_ID_GENERATION_SCRIPT, None)
if group_id_generator is None:
raise RuntimeError, '%s script was not found' % ERP5TYPE_SECURITY_GROUP_ID_GENERATION_SCRIPT
for role, value_list in role_category_list.items():
if not role_group_id_dict.has_key(role):
role_group_id_dict[role] = []
role_group_dict = {}
for category_dict in value_list:
group_id = group_id_generator(**category_dict)
role_group_dict[group_id] = 1
role_group_id_dict[role].extend(role_group_dict.keys())
#Switch index from role to group id
group_id_role_dict = {}
for role, group_list in role_group_id_dict.items():
for group_id in group_list:
if not group_id_role_dict.has_key(group_id):
group_id_role_dict[group_id] = []
group_id_role_dict[group_id].append(role)
#Clean old group roles
old_group_list = object.get_local_group_roles()
object.manage_delLocalGroupRoles([x[0] for x in old_group_list])
#Assign new roles
for group, role_list in group_id_role_dict.items():
object.manage_addLocalGroupRoles(group, role_list)
security.declarePublic('getFilteredRoleListFor')
def getFilteredRoleListFor(self, object=None, **kw):
"""
......
......@@ -31,7 +31,7 @@ from types import StringType
class RoleInformation( SimpleItem ):
""" Represent a single selectable role.
Roles generate links to views of content, or to specific methods
of the site. They can be filtered via their conditions.
"""
......@@ -48,24 +48,21 @@ class RoleInformation( SimpleItem ):
, condition=''
, priority=10
, base_category=()
, user=''
, base_category_script=''
):
""" Set up an instance.
"""
if condition and type( condition ) == type( '' ):
condition = Expression( condition )
if user and type( user ) == type( '' ):
user = Expression( user )
self.id = id
self.title = title
self.description = description
self.category = category
self.category = category
self.condition = condition
self.priority = priority
self.priority = priority
self.base_category = base_category
self.user = user
self.base_category_script = base_category_script
security.declareProtected( View, 'Title' )
def Title(self):
......@@ -100,36 +97,10 @@ class RoleInformation( SimpleItem ):
info = {}
info['id'] = self.id
info['name'] = self.Title()
expr = self.getUserExpression()
__traceback_info__ = (info['id'], info['name'], expr)
if self.user:
info['user'] = self.user( ec ) or None
else:
info['user'] = getSecurityManager().getUser() # XXX The user should be a handle to the Person object
info['category'] = self.getCategory()
info['base_category'] = self.getBaseCategory()
return info
security.declarePublic( 'getUserExpression' )
def getUserExpression( self ):
""" Return the text of the TALES expression for our URL.
"""
user = getattr(self, 'user', '')
expr = user and user.text or ''
if expr and type( expr ) is StringType:
if not expr.startswith('python:') and not expr.startswith('string:'):
expr = 'string:${object_url}/%s' % expr
self.user = Expression( expr )
return expr
security.declarePrivate( 'setRoleExpression' )
def setUserExpression(self, user):
if user and type( user ) is StringType:
if not user.startswith('python:') and not user.startswith('string:'):
user = 'string:${object_url}/%s' % user
user = Expression( user )
self.user = user
info['base_category_script'] = self.getBaseCategoryScript()
return info
security.declarePublic( 'getCondition' )
def getCondition(self):
......@@ -141,9 +112,9 @@ class RoleInformation( SimpleItem ):
security.declarePublic( 'getCategory' )
def getCategory( self ):
""" Return the category
""" Return the category
as a tuple (to prevent script from modifying it)
Strip any return or ending space
"""
return tuple(map(lambda x: x.strip(), filter(lambda x: x, self.category))) or ()
......@@ -156,6 +127,13 @@ class RoleInformation( SimpleItem ):
"""
return tuple(getattr(self, 'base_category', ()))
security.declarePublic( 'getBaseCategoryScript' )
def getBaseCategoryScript( self ):
""" Return the base_category_script id
"""
return getattr(self, 'base_category_script', '')
security.declarePrivate( 'base_category' )
def clone( self ):
......@@ -168,7 +146,7 @@ class RoleInformation( SimpleItem ):
, condition=self.getCondition()
, priority =self.priority
, base_category=self.base_category
, user=self.getUserExpression()
, base_category_script=self.base_category_script
)
InitializeClass( RoleInformation )
......@@ -182,8 +160,8 @@ class ori:
def __init__( self, tool, folder, object=None ):
self.portal = portal = aq_parent(aq_inner(tool))
membership = getToolByName(tool, 'portal_membership')
self.isAnonymous = membership.isAnonymousUser()
self.user_id = membership.getAuthenticatedMember().getId()
#self.isAnonymous = membership.isAnonymousUser()
#self.user_id = membership.getAuthenticatedMember().getId()
self.portal_url = portal.absolute_url()
if folder is not None:
self.folder_url = folder.absolute_url()
......
......@@ -41,7 +41,7 @@ class RoleProviderBase:
manage_options = ( { 'label' : 'Roles'
, 'action' : 'manage_editRolesForm'
}
,
,
)
#
......@@ -70,7 +70,7 @@ class RoleProviderBase:
a1['name'] = a.Title() # The name of this role definition (ex. Assignor at company X)
a1['category'] = a.getCategory() or [] # Category definition
a1['base_category'] = a.getBaseCategory() # Base Category Definition
a1['user'] = a.getUserExpression()
a1['base_category_script'] = a.getBaseCategoryScript() # Base Category Script Id
a1['condition'] = a.getCondition()
roles.append(a1)
......@@ -85,9 +85,9 @@ class RoleProviderBase:
def addRole( self
, id
, name
, user
, condition
, category
, base_category_script
, base_category=()
, REQUEST=None
):
......@@ -96,17 +96,16 @@ class RoleProviderBase:
if not name:
raise ValueError('A name is required.')
a_expr = user and Expression(text=str(user)) or ''
c_expr = condition and Expression(text=str(condition)) or ''
new_roles = self._cloneRoles()
new_role = RoleInformation( id=str(id)
, title=str(name)
, user=a_expr
, condition=c_expr
, category=category.split('\n')
, base_category=base_category.split()
, base_category_script=base_category_script
)
new_roles.append( new_role )
......@@ -220,7 +219,7 @@ class RoleProviderBase:
""" Return a list of roles, cloned from our current list.
"""
return map( lambda x: x.clone(), list( self._roles ) )
security.declarePrivate( '_extractRole' )
def _extractRole( self, properties, index ):
......@@ -228,26 +227,23 @@ class RoleProviderBase:
"""
id = str( properties.get( 'id_%d' % index, '' ) )
name = str( properties.get( 'name_%d' % index, '' ) )
user = str( properties.get( 'user_%d' % index, '' ) )
condition = str( properties.get( 'condition_%d' % index, '' ) )
category = properties.get( 'category_%d' % index, '' ).split('\n')
base_category = properties.get( 'base_category_%d' % index, '' ).split()
base_category_script = str( properties.get( 'base_category_script_%d' % index, '' ) )
if not name:
raise ValueError('A name is required.')
if user is not '':
user = Expression( text=user )
if condition is not '':
condition = Expression( text=condition )
return RoleInformation( id=id
, title=name
, user=user
, condition=condition
, category=category
, base_category=base_category
, base_category_script=base_category_script
)
InitializeClass(RoleProviderBase)
......@@ -56,7 +56,7 @@
<td></td>
<td>
<div class="form-label">
Condition
Condition
</div>
</td>
<td>
......@@ -70,12 +70,12 @@
<td></td>
<td>
<div class="form-label">
User
Base Category
</div>
</td>
<td>
<div class="form-element">
<input type="text" name="user_&dtml-index;" value="&dtml-user;" size="80" />
<input type="text" size="40" name="base_category_&dtml-index;" value="<dtml-var "' '.join(base_category)">" />
</div>
</td>
</tr>
......@@ -84,12 +84,12 @@
<td></td>
<td>
<div class="form-label">
Base Category
Base Category Script
</div>
</td>
<td>
<div class="form-element">
<input type="text" size="40" name="base_category_&dtml-index;" value="<dtml-var "' '.join(base_category)">" />
<input type="text" name="base_category_script_&dtml-index;" value="&dtml-base_category_script;" size="80" />
</div>
</td>
</tr>
......@@ -169,7 +169,7 @@ Add a role
<td></td>
<td>
<div class="form-label">
Condition
Condition
</div>
</td>
<td>
......@@ -183,12 +183,12 @@ Add a role
<td></td>
<td>
<div class="form-label">
User
Base Category
</div>
</td>
<td>
<div class="form-element">
<input type="text" name="user" size="80" />
<input type="text" size="40" name="base_category" />
</div>
</td>
</tr>
......@@ -197,12 +197,12 @@ Add a role
<td></td>
<td>
<div class="form-label">
Base Category
Base Category Script
</div>
</td>
<td>
<div class="form-element">
<input type="text" size="40" name="base_category" />
<input type="text" name="base_category_script" size="80" />
</div>
</td>
</tr>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment