[PATCH 4 of 4 saem] [security] Update security of the authority record kind relation

Sylvain Thenault sylvain.thenault at logilab.fr
Thu Apr 13 11:00:02 CEST 2017


# HG changeset patch
# User Sylvain Thénault <sylvain.thenault at logilab.fr>
# Date 1492070281 -7200
#      Thu Apr 13 09:58:01 2017 +0200
# Node ID a3945adaf0b1d9b6bc0713413610b3c0eaebdceb
# Parent  19025cca31f03f035616ce1995cfbecb728d46c3
[security] Update security of the authority record kind relation

(still named agent_kind for historical reason).

In the eac cube, this relation can't be modified unless its value is 'unknown'.
Here we want to allow modification provided that the record isn't referenced by
authority_record relation which add constraint on the kind's value.

To achieve this, update the relation's permission to depends on its subject
entity's permission, then add a constraint to ensure consistency of
authority_record wrt kind's value.

Related to #16385734

diff --git a/cubicweb_saem_ref/migration/0.15.1_Any.py b/cubicweb_saem_ref/migration/0.15.1_Any.py
--- a/cubicweb_saem_ref/migration/0.15.1_Any.py
+++ b/cubicweb_saem_ref/migration/0.15.1_Any.py
@@ -1,7 +1,7 @@
 for ertype in ('generated', 'used', 'associated_with', 'place_address', 'new_version_of',
-               'authority_record',
+               'agent_kind', 'authority_record',
                'OrganizationUnit', 'Agent', 'ArkNameAssigningAuthority'):
     sync_schema_props_perms(ertype)
 
 
 sql("DELETE FROM container_relation WHERE EXISTS("
diff --git a/cubicweb_saem_ref/schema.py b/cubicweb_saem_ref/schema.py
--- a/cubicweb_saem_ref/schema.py
+++ b/cubicweb_saem_ref/schema.py
@@ -86,10 +86,26 @@ EmailAddress.remove_relation('alias')
 
 # Customization of eac schema.
 make_workflowable(eac.AuthorityRecord)
 groups_permissions(eac.AuthorityRecord)
 
+eac.agent_kind.__permissions__ = {
+    'read': ('managers', 'users', 'guests'),
+    'add': ('managers', RRQLExpression('U has_update_permission S')),
+    'delete': ('managers', RRQLExpression('U has_update_permission S')),
+}
+eac.agent_kind.constraints = [
+    RQLConstraint('NOT EXISTS(Z authority_record S)'
+                  ' OR '
+                  'EXISTS(A authority_record S, A is Agent, '
+                  '       S agent_kind K, K name "person")'
+                  ' OR '
+                  'EXISTS(OU authority_record S, OU is IN (Organization, OrganizationUnit), '
+                  '       S agent_kind K, K name "authority")',
+                  msg=_('This record is used by a relation forbidding to change its type')),
+]
+
 
 # Customization of skos schema.
 make_workflowable(ConceptScheme)
 publication_permissions(ConceptScheme)
 
diff --git a/test/test_security.py b/test/test_security.py
--- a/test/test_security.py
+++ b/test/test_security.py
@@ -45,10 +45,15 @@ class NonManagerUserTC(CubicWebTC):
             arecord = testutils.authority_record(cnx, name=u'a')
             cnx.commit()
             arecord.cw_set(record_id=u'123')
             cnx.commit()
 
+            # can change kind (unless used in constrained relation, but this is tested in
+            # unittest_schema)
+            arecord.cw_set(agent_kind=cnx.find('AgentKind', name=u'authority').one())
+            cnx.commit()
+
     def test_create_update_sedaprofile(self):
         with self.new_access(self.login).cnx() as cnx:
             profile = testutils.setup_profile(cnx)
             cnx.commit()
             profile.cw_set(user_annotation=u'meh')
diff --git a/test/unittest_schema.py b/test/unittest_schema.py
--- a/test/unittest_schema.py
+++ b/test/unittest_schema.py
@@ -90,10 +90,40 @@ class SchemaConstraintsTC(CubicWebTC):
             self.assertEqual(
                 pou.unrelated('authority_record', 'AuthorityRecord').one(),
                 cnx.find("AuthorityRecord", has_text=u"Direction de la communication").one(),
             )
 
+    def assertCantChangeRecordKind(self, arecord, kind):
+        cnx = arecord._cw
+        with self.assertValidationError(cnx) as cm:
+            arecord.cw_set(agent_kind=cnx.find('AgentKind', name=kind).one())
+            cnx.commit()
+        self.assertEqual(cm.exception.errors,
+                         {'agent_kind-subject':
+                          'This record is used by a relation forbidding to change its type'})
+
+    def test_authority_record_kind_consistency(self):
+        with self.admin_access.repo_cnx() as cnx:
+            arecord = testutils.authority_record(cnx, u'service', kind=u'authority')
+            testutils.organization_unit(cnx, u'unit', authority_record=arecord)
+            cnx.commit()
+
+            self.assertCantChangeRecordKind(arecord, u'person')
+
+            org = testutils.authority_with_naa(cnx)
+            org.cw_set(authority_record=arecord)
+            cnx.commit()
+            self.assertCantChangeRecordKind(arecord, u'person')
+
+            org.cw_set(authority_record=None)
+            arecord.cw_set(agent_kind=cnx.find('AgentKind', name=u'person').one())
+            cnx.commit()
+
+            testutils.agent(cnx, u'bob', authority_record=arecord)
+            cnx.commit()
+            self.assertCantChangeRecordKind(arecord, u'authority')
+
     def test_organization_unit_contact_point_in_the_same_authority(self):
         """Create two agents on two distinct authorities. Create an organization unit and check that
         interface will only show consistent proposal for contact point
         """
         with self.admin_access.repo_cnx() as cnx:


More information about the saem-devel mailing list