Commit ba7f44cf authored by Georgios Dagkakis's avatar Georgios Dagkakis

Standard security calculation to check if Assignment is expired or not

security calculation checks the validation state of the Assignment, but it should also check if it is expired or not started yet.

This merge request applies fix, extending tests to re-produce and test the situation.
Also, a cleanup in erp5_core: extension.erp5.StandardSecurity.

/reviewed-on nexedi/erp5!548
parents 7e016536 cc3a8079
...@@ -24,12 +24,16 @@ ...@@ -24,12 +24,16 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
############################################################################## ##############################################################################
from DateTime import DateTime
from Products.ERP5Security.ERP5GroupManager import ConsistencyError def getSecurityCategoryFromAssignment(
from Products.ZSQLCatalog.SQLCatalog import SimpleQuery self,
base_category_list,
def getSecurityCategoryFromAssignment(self, base_category_list, user_name, object, portal_type, user_name,
child_category_list=[]): object, # pylint: disable=redefined-builtin
portal_type,
child_category_list=None
):
""" """
This script returns a list of dictionaries which represent This script returns a list of dictionaries which represent
the security groups which a person is member of. It extracts the security groups which a person is member of. It extracts
...@@ -49,9 +53,9 @@ def getSecurityCategoryFromAssignment(self, base_category_list, user_name, objec ...@@ -49,9 +53,9 @@ def getSecurityCategoryFromAssignment(self, base_category_list, user_name, objec
object -- object which we want to assign roles to object -- object which we want to assign roles to
portal_type -- portal type of object portal_type -- portal type of object
""" """
context = self
category_list = [] category_list = []
if child_category_list is None:
child_category_list = []
user_path_set = { user_path_set = {
x['path'] for x in self.acl_users.searchUsers( x['path'] for x in self.acl_users.searchUsers(
...@@ -66,10 +70,15 @@ def getSecurityCategoryFromAssignment(self, base_category_list, user_name, objec ...@@ -66,10 +70,15 @@ def getSecurityCategoryFromAssignment(self, base_category_list, user_name, objec
return [] return []
user_path, = user_path_set user_path, = user_path_set
person_object = self.getPortalObject().unrestrictedTraverse(user_path) person_object = self.getPortalObject().unrestrictedTraverse(user_path)
now = DateTime()
# We look for every valid assignments of this user # We look for every valid assignments of this user
for assignment in person_object.contentValues(filter={'portal_type': 'Assignment'}): for assignment in person_object.contentValues(filter={'portal_type': 'Assignment'}):
if assignment.getValidationState() == 'open': if assignment.getValidationState() == "open" and (
not assignment.hasStartDate() or assignment.getStartDate() <= now
) and (
not assignment.hasStopDate() or assignment.getStopDate() >= now
):
category_dict = {} category_dict = {}
for base_category in base_category_list: for base_category in base_category_list:
category_value_list = assignment.getAcquiredValueList(base_category) category_value_list = assignment.getAcquiredValueList(base_category)
...@@ -89,22 +98,31 @@ def getSecurityCategoryFromAssignment(self, base_category_list, user_name, objec ...@@ -89,22 +98,31 @@ def getSecurityCategoryFromAssignment(self, base_category_list, user_name, objec
return category_list return category_list
def getSecurityCategoryFromAssignmentParent(self, base_category_list, def getSecurityCategoryFromAssignmentParent(self, base_category_list, user_name,
user_name, object, portal_type): object, # pylint: disable=redefined-builtin
return getSecurityCategoryFromAssignment(self, base_category_list, portal_type):
user_name, object, portal_type, child_category_list=base_category_list) return getSecurityCategoryFromAssignment(self, base_category_list, user_name,
object, # pylint: disable=redefined-builtin
portal_type, child_category_list=base_category_list)
def getSecurityCategoryFromAssignmentParentGroup(self, base_category_list, user_name,
object, # pylint: disable=redefined-builtin
portal_type):
return getSecurityCategoryFromAssignment(self, base_category_list, user_name,
object, # pylint: disable=redefined-builtin
portal_type, child_category_list=('group',))
def getSecurityCategoryFromAssignmentParentGroup(self, base_category_list, def getSecurityCategoryFromAssignmentParentFunction(self, base_category_list, user_name,
user_name, object, portal_type): object, # pylint: disable=redefined-builtin
return getSecurityCategoryFromAssignment(self, base_category_list, portal_type):
user_name, object, portal_type, child_category_list=('group',)) return getSecurityCategoryFromAssignment(self, base_category_list, user_name,
object, # pylint: disable=redefined-builtin
portal_type, child_category_list=('function',))
def getSecurityCategoryFromAssignmentParentFunction(self, base_category_list, def getSecurityCategoryFromAssignmentParentFunctionParentGroup(self, base_category_list, user_name,
user_name, object, portal_type): object, # pylint: disable=redefined-builtin
return getSecurityCategoryFromAssignment(self, base_category_list, portal_type):
user_name, object, portal_type, child_category_list=('function',)) return getSecurityCategoryFromAssignment(self, base_category_list, user_name,
object, # pylint: disable=redefined-builtin
portal_type, child_category_list=('function', 'group'))
def getSecurityCategoryFromAssignmentParentFunctionParentGroup(self, base_category_list,
user_name, object, portal_type):
return getSecurityCategoryFromAssignment(self, base_category_list,
user_name, object, portal_type, child_category_list=('function', 'group'))
...@@ -6,10 +6,22 @@ ...@@ -6,10 +6,22 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>StandardSecurity</string> </value> <value> <string>StandardSecurity</string> </value>
</item> </item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>extension.erp5.StandardSecurity</string> </value> <value> <string>extension.erp5.StandardSecurity</string> </value>
...@@ -24,6 +36,18 @@ ...@@ -24,6 +36,18 @@
<none/> <none/>
</value> </value>
</item> </item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item> <item>
<key> <string>version</string> </key> <key> <string>version</string> </key>
<value> <string>erp5</string> </value> <value> <string>erp5</string> </value>
...@@ -31,13 +55,28 @@ ...@@ -31,13 +55,28 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -50,7 +89,7 @@ ...@@ -50,7 +89,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -59,7 +98,7 @@ ...@@ -59,7 +98,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="3" aka="AAAAAAAAAAM="> <record id="4" aka="AAAAAAAAAAQ=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle> </pickle>
......
...@@ -105,7 +105,7 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -105,7 +105,7 @@ class TestUserManagement(ERP5TypeTestCase):
newSecurityManager(None, user) newSecurityManager(None, user)
def _makePerson(self, login=AUTO_LOGIN, open_assignment=1, assignment_start_date=None, def _makePerson(self, login=AUTO_LOGIN, open_assignment=1, assignment_start_date=None,
assignment_stop_date=None, tic=True, password='secret', **kw): assignment_stop_date=None, tic=True, password='secret', group_value=None, **kw):
"""Creates a person in person module, and returns the object, after """Creates a person in person module, and returns the object, after
indexing is done. """ indexing is done. """
person_module = self.getPersonModule() person_module = self.getPersonModule()
...@@ -113,7 +113,8 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -113,7 +113,8 @@ class TestUserManagement(ERP5TypeTestCase):
portal_type='Person', **kw) portal_type='Person', **kw)
assignment = new_person.newContent(portal_type = 'Assignment', assignment = new_person.newContent(portal_type = 'Assignment',
start_date=assignment_start_date, start_date=assignment_start_date,
stop_date=assignment_stop_date,) stop_date=assignment_stop_date,
group_value=group_value,)
if open_assignment: if open_assignment:
assignment.open() assignment.open()
if login is not None: if login is not None:
...@@ -160,6 +161,48 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -160,6 +161,48 @@ class TestUserManagement(ERP5TypeTestCase):
"Plugin %s should not have authenticated '%s' with password '%s'" % "Plugin %s should not have authenticated '%s' with password '%s'" %
(plugin_name, login, password)) (plugin_name, login, password))
def _getOrCreateGroupValue(self):
group_id = 'dummy_group'
group = self.portal.portal_categories.group
if group_id in group.objectIds():
return group[group_id]
else:
return self.portal.portal_categories.group.newContent(
id=group_id
)
def _createDummyDocument(self):
types_tool = self.portal.portal_types
# Create Portal Types if needed
if 'Dummy Object' not in types_tool.objectIds():
dummy_type = types_tool.newContent(
'Dummy Object',
'Base Type',
type_class='XMLObject'
)
dummy_type.newContent(
portal_type='Role Information',
role_category_list=self.portal.portal_categories.\
group.dummy_group.getRelativeUrl(),
role_name_list=('Assignee', )
)
if 'Dummy Module' not in types_tool.objectIds():
types_tool.newContent(
'Dummy Module',
'Base Type',
type_class='Folder',
type_filter_content_type=1,
type_allowed_content_type_list=('Dummy Object', ),
)
# clean-up dummy_module in any way
if 'dummy_module' in self.portal.objectIds():
self.portal.manage_delObjects(['dummy_module'])
self.tic()
self.portal.newContent(portal_type='Dummy Module', id='dummy_module')
dummy_document = self.portal.dummy_module.newContent(portal_type='Dummy Object')
self.tic()
return dummy_document
def test_PersonWithLoginPasswordAreUsers(self): def test_PersonWithLoginPasswordAreUsers(self):
"""Tests a person with a login & password is a valid user.""" """Tests a person with a login & password is a valid user."""
_, login, password = self._makePerson() _, login, password = self._makePerson()
...@@ -546,6 +589,57 @@ class TestUserManagement(ERP5TypeTestCase): ...@@ -546,6 +589,57 @@ class TestUserManagement(ERP5TypeTestCase):
) )
self._assertUserDoesNotExists(login, password) self._assertUserDoesNotExists(login, password)
def test_securityGroupAssignmentCorrectDate(self):
"""
Tests a person with an assignment with correct date
gets correctly assigned to security groups.
"""
date = DateTime()
user_id, login, password = self._makePerson(
assignment_start_date=date - 5,
assignment_stop_date=date + 5,
group_value=self._getOrCreateGroupValue()
)
self.assertIn(
'Assignee',
self.portal.acl_users.getUserById(user_id).\
getRolesInContext(self._createDummyDocument())
)
def test_securityGroupAssignmentBadStartDate(self):
"""
Tests a person with an assignment with bad (future) start date
does not get assigned to security groups.
"""
date = DateTime()
user_id, login, password = self._makePerson(
assignment_start_date=date + 1,
assignment_stop_date=date + 5,
group_value=self._getOrCreateGroupValue()
)
self.assertNotIn(
'Assignee',
self.portal.acl_users.getUserById(user_id).\
getRolesInContext(self._createDummyDocument())
)
def test_securityGroupAssignmentBadStopDate(self):
"""
Tests a person with an assignment with bad (past) stop date
does not get assigned to security groups.
"""
date = DateTime()
user_id, login, password = self._makePerson(
assignment_start_date=date - 5,
assignment_stop_date=date - 1,
group_value=self._getOrCreateGroupValue()
)
self.assertNotIn(
'Assignee',
self.portal.acl_users.getUserById(user_id).\
getRolesInContext(self._createDummyDocument())
)
def test_DeletedPersonIsNotUser(self): def test_DeletedPersonIsNotUser(self):
user_id, login, password = self._makePerson() user_id, login, password = self._makePerson()
self._assertUserExists(login, password) self._assertUserExists(login, password)
......
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