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 @@ ...@@ -21,7 +21,7 @@
############################################################################## ##############################################################################
from Globals import InitializeClass, DTMLFile from Globals import InitializeClass, DTMLFile
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo, getSecurityManager
from Acquisition import aq_base, aq_inner, aq_parent from Acquisition import aq_base, aq_inner, aq_parent
import Products.CMFCore.TypesTool import Products.CMFCore.TypesTool
...@@ -39,7 +39,7 @@ from RoleInformation import ori ...@@ -39,7 +39,7 @@ from RoleInformation import ori
from zLOG import LOG from zLOG import LOG
ERP5TYPE_ROLE_INIT_SCRIPT = 'ERP5Type_initLocalRoleMapping' ERP5TYPE_SECURITY_GROUP_ID_GENERATION_SCRIPT = 'ERP5TypeSecurity_asGroupId'
class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
""" """
...@@ -106,7 +106,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -106,7 +106,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
hidden_content_type_list = () hidden_content_type_list = ()
filter_actions = 0 filter_actions = 0
allowed_action_list = [] allowed_action_list = []
# #
# Acquisition editing interface # Acquisition editing interface
# #
...@@ -119,7 +119,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -119,7 +119,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
""" """
self.setMethodAliases({}) self.setMethodAliases({})
return 1 return 1
security.declarePublic('hideFromAddMenu') security.declarePublic('hideFromAddMenu')
def hidenFromAddMenu(self): def hidenFromAddMenu(self):
""" """
...@@ -140,24 +140,18 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -140,24 +140,18 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
""" """
ob = FactoryTypeInformation.constructInstance(self, container, id, *args, **kw) ob = FactoryTypeInformation.constructInstance(self, container, id, *args, **kw)
# Only try to find the local role init script # Only try to assign roles to secutiry groups if some roles are defined
# if some roles are defined
# This is an optimisation to prevent defining local roles on subobjects # This is an optimisation to prevent defining local roles on subobjects
# which acquire their security definition from their parent # 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 # set a local role definition if the local role list is empty
if len(self._roles): if len(self._roles):
init_role_script = getattr(ob, ERP5TYPE_ROLE_INIT_SCRIPT, None) self.assignRoleToSecurityGroup(ob)
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)
if self.init_script: if self.init_script:
# Acquire the init script in the context of this object # Acquire the init script in the context of this object
init_script = getattr(ob, self.init_script) init_script = getattr(ob, self.init_script)
init_script(*args, **kw) init_script(*args, **kw)
return ob return ob
...@@ -193,6 +187,79 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -193,6 +187,79 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
result.sort() result.sort()
return result 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') security.declarePublic('getFilteredRoleListFor')
def getFilteredRoleListFor(self, object=None, **kw): def getFilteredRoleListFor(self, object=None, **kw):
""" """
......
...@@ -31,7 +31,7 @@ from types import StringType ...@@ -31,7 +31,7 @@ from types import StringType
class RoleInformation( SimpleItem ): class RoleInformation( SimpleItem ):
""" Represent a single selectable role. """ Represent a single selectable role.
Roles generate links to views of content, or to specific methods Roles generate links to views of content, or to specific methods
of the site. They can be filtered via their conditions. of the site. They can be filtered via their conditions.
""" """
...@@ -48,24 +48,21 @@ class RoleInformation( SimpleItem ): ...@@ -48,24 +48,21 @@ class RoleInformation( SimpleItem ):
, condition='' , condition=''
, priority=10 , priority=10
, base_category=() , base_category=()
, user='' , base_category_script=''
): ):
""" Set up an instance. """ Set up an instance.
""" """
if condition and type( condition ) == type( '' ): if condition and type( condition ) == type( '' ):
condition = Expression( condition ) condition = Expression( condition )
if user and type( user ) == type( '' ):
user = Expression( user )
self.id = id self.id = id
self.title = title self.title = title
self.description = description self.description = description
self.category = category self.category = category
self.condition = condition self.condition = condition
self.priority = priority self.priority = priority
self.base_category = base_category self.base_category = base_category
self.user = user self.base_category_script = base_category_script
security.declareProtected( View, 'Title' ) security.declareProtected( View, 'Title' )
def Title(self): def Title(self):
...@@ -100,36 +97,10 @@ class RoleInformation( SimpleItem ): ...@@ -100,36 +97,10 @@ class RoleInformation( SimpleItem ):
info = {} info = {}
info['id'] = self.id info['id'] = self.id
info['name'] = self.Title() 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['category'] = self.getCategory()
info['base_category'] = self.getBaseCategory() info['base_category'] = self.getBaseCategory()
return info info['base_category_script'] = self.getBaseCategoryScript()
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
security.declarePublic( 'getCondition' ) security.declarePublic( 'getCondition' )
def getCondition(self): def getCondition(self):
...@@ -141,9 +112,9 @@ class RoleInformation( SimpleItem ): ...@@ -141,9 +112,9 @@ class RoleInformation( SimpleItem ):
security.declarePublic( 'getCategory' ) security.declarePublic( 'getCategory' )
def getCategory( self ): def getCategory( self ):
""" Return the category """ Return the category
as a tuple (to prevent script from modifying it) as a tuple (to prevent script from modifying it)
Strip any return or ending space Strip any return or ending space
""" """
return tuple(map(lambda x: x.strip(), filter(lambda x: x, self.category))) or () return tuple(map(lambda x: x.strip(), filter(lambda x: x, self.category))) or ()
...@@ -156,6 +127,13 @@ class RoleInformation( SimpleItem ): ...@@ -156,6 +127,13 @@ class RoleInformation( SimpleItem ):
""" """
return tuple(getattr(self, 'base_category', ())) 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' ) security.declarePrivate( 'base_category' )
def clone( self ): def clone( self ):
...@@ -168,7 +146,7 @@ class RoleInformation( SimpleItem ): ...@@ -168,7 +146,7 @@ class RoleInformation( SimpleItem ):
, condition=self.getCondition() , condition=self.getCondition()
, priority =self.priority , priority =self.priority
, base_category=self.base_category , base_category=self.base_category
, user=self.getUserExpression() , base_category_script=self.base_category_script
) )
InitializeClass( RoleInformation ) InitializeClass( RoleInformation )
...@@ -182,8 +160,8 @@ class ori: ...@@ -182,8 +160,8 @@ class ori:
def __init__( self, tool, folder, object=None ): def __init__( self, tool, folder, object=None ):
self.portal = portal = aq_parent(aq_inner(tool)) self.portal = portal = aq_parent(aq_inner(tool))
membership = getToolByName(tool, 'portal_membership') membership = getToolByName(tool, 'portal_membership')
self.isAnonymous = membership.isAnonymousUser() #self.isAnonymous = membership.isAnonymousUser()
self.user_id = membership.getAuthenticatedMember().getId() #self.user_id = membership.getAuthenticatedMember().getId()
self.portal_url = portal.absolute_url() self.portal_url = portal.absolute_url()
if folder is not None: if folder is not None:
self.folder_url = folder.absolute_url() self.folder_url = folder.absolute_url()
......
...@@ -41,7 +41,7 @@ class RoleProviderBase: ...@@ -41,7 +41,7 @@ class RoleProviderBase:
manage_options = ( { 'label' : 'Roles' manage_options = ( { 'label' : 'Roles'
, 'action' : 'manage_editRolesForm' , 'action' : 'manage_editRolesForm'
} }
, ,
) )
# #
...@@ -70,7 +70,7 @@ class RoleProviderBase: ...@@ -70,7 +70,7 @@ class RoleProviderBase:
a1['name'] = a.Title() # The name of this role definition (ex. Assignor at company X) a1['name'] = a.Title() # The name of this role definition (ex. Assignor at company X)
a1['category'] = a.getCategory() or [] # Category definition a1['category'] = a.getCategory() or [] # Category definition
a1['base_category'] = a.getBaseCategory() # Base 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() a1['condition'] = a.getCondition()
roles.append(a1) roles.append(a1)
...@@ -85,9 +85,9 @@ class RoleProviderBase: ...@@ -85,9 +85,9 @@ class RoleProviderBase:
def addRole( self def addRole( self
, id , id
, name , name
, user
, condition , condition
, category , category
, base_category_script
, base_category=() , base_category=()
, REQUEST=None , REQUEST=None
): ):
...@@ -96,17 +96,16 @@ class RoleProviderBase: ...@@ -96,17 +96,16 @@ class RoleProviderBase:
if not name: if not name:
raise ValueError('A name is required.') raise ValueError('A name is required.')
a_expr = user and Expression(text=str(user)) or ''
c_expr = condition and Expression(text=str(condition)) or '' c_expr = condition and Expression(text=str(condition)) or ''
new_roles = self._cloneRoles() new_roles = self._cloneRoles()
new_role = RoleInformation( id=str(id) new_role = RoleInformation( id=str(id)
, title=str(name) , title=str(name)
, user=a_expr
, condition=c_expr , condition=c_expr
, category=category.split('\n') , category=category.split('\n')
, base_category=base_category.split() , base_category=base_category.split()
, base_category_script=base_category_script
) )
new_roles.append( new_role ) new_roles.append( new_role )
...@@ -220,7 +219,7 @@ class RoleProviderBase: ...@@ -220,7 +219,7 @@ class RoleProviderBase:
""" Return a list of roles, cloned from our current list. """ Return a list of roles, cloned from our current list.
""" """
return map( lambda x: x.clone(), list( self._roles ) ) return map( lambda x: x.clone(), list( self._roles ) )
security.declarePrivate( '_extractRole' ) security.declarePrivate( '_extractRole' )
def _extractRole( self, properties, index ): def _extractRole( self, properties, index ):
...@@ -228,26 +227,23 @@ class RoleProviderBase: ...@@ -228,26 +227,23 @@ class RoleProviderBase:
""" """
id = str( properties.get( 'id_%d' % index, '' ) ) id = str( properties.get( 'id_%d' % index, '' ) )
name = str( properties.get( 'name_%d' % index, '' ) ) name = str( properties.get( 'name_%d' % index, '' ) )
user = str( properties.get( 'user_%d' % index, '' ) )
condition = str( properties.get( 'condition_%d' % index, '' ) ) condition = str( properties.get( 'condition_%d' % index, '' ) )
category = properties.get( 'category_%d' % index, '' ).split('\n') category = properties.get( 'category_%d' % index, '' ).split('\n')
base_category = properties.get( 'base_category_%d' % index, '' ).split() base_category = properties.get( 'base_category_%d' % index, '' ).split()
base_category_script = str( properties.get( 'base_category_script_%d' % index, '' ) )
if not name: if not name:
raise ValueError('A name is required.') raise ValueError('A name is required.')
if user is not '':
user = Expression( text=user )
if condition is not '': if condition is not '':
condition = Expression( text=condition ) condition = Expression( text=condition )
return RoleInformation( id=id return RoleInformation( id=id
, title=name , title=name
, user=user
, condition=condition , condition=condition
, category=category , category=category
, base_category=base_category , base_category=base_category
, base_category_script=base_category_script
) )
InitializeClass(RoleProviderBase) InitializeClass(RoleProviderBase)
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
<td></td> <td></td>
<td> <td>
<div class="form-label"> <div class="form-label">
Condition Condition
</div> </div>
</td> </td>
<td> <td>
...@@ -70,12 +70,12 @@ ...@@ -70,12 +70,12 @@
<td></td> <td></td>
<td> <td>
<div class="form-label"> <div class="form-label">
User Base Category
</div> </div>
</td> </td>
<td> <td>
<div class="form-element"> <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> </div>
</td> </td>
</tr> </tr>
...@@ -84,12 +84,12 @@ ...@@ -84,12 +84,12 @@
<td></td> <td></td>
<td> <td>
<div class="form-label"> <div class="form-label">
Base Category Base Category Script
</div> </div>
</td> </td>
<td> <td>
<div class="form-element"> <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> </div>
</td> </td>
</tr> </tr>
...@@ -169,7 +169,7 @@ Add a role ...@@ -169,7 +169,7 @@ Add a role
<td></td> <td></td>
<td> <td>
<div class="form-label"> <div class="form-label">
Condition Condition
</div> </div>
</td> </td>
<td> <td>
...@@ -183,12 +183,12 @@ Add a role ...@@ -183,12 +183,12 @@ Add a role
<td></td> <td></td>
<td> <td>
<div class="form-label"> <div class="form-label">
User Base Category
</div> </div>
</td> </td>
<td> <td>
<div class="form-element"> <div class="form-element">
<input type="text" name="user" size="80" /> <input type="text" size="40" name="base_category" />
</div> </div>
</td> </td>
</tr> </tr>
...@@ -197,12 +197,12 @@ Add a role ...@@ -197,12 +197,12 @@ Add a role
<td></td> <td></td>
<td> <td>
<div class="form-label"> <div class="form-label">
Base Category Base Category Script
</div> </div>
</td> </td>
<td> <td>
<div class="form-element"> <div class="form-element">
<input type="text" size="40" name="base_category" /> <input type="text" name="base_category_script" size="80" />
</div> </div>
</td> </td>
</tr> </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