Blame SOURCES/0001-Issue-4678-RFE-automatique-disable-of-virtual-attrib.patch

51b5b9
From 67e19da62a9e8958458de54173dcd9bcaf53164d Mon Sep 17 00:00:00 2001
51b5b9
From: tbordaz <tbordaz@redhat.com>
51b5b9
Date: Thu, 30 Sep 2021 15:59:40 +0200
51b5b9
Subject: [PATCH 01/12] Issue 4678 - RFE automatique disable of virtual
51b5b9
 attribute checking (#4918)
51b5b9
51b5b9
Bug description:
51b5b9
	Virtual attributes are configured via Roles or COS definitions
51b5b9
        and registered during initialization of those plugins.
51b5b9
	Virtual attributes are processed during search evaluation of
51b5b9
	filter and returned attributes. This processing is expensive
51b5b9
	and prone to create contention between searches.
51b5b9
	Use of virtual attribute is not frequent. So many of the
51b5b9
	deployement process virtual attribute even if there is none.
51b5b9
51b5b9
Fix description:
51b5b9
	The fix configure the server to ignore virtual attribute by
51b5b9
        default (nsslapd-ignore-virtual-attrs: on).
51b5b9
        At startup, if a new virtual attribute is registered or
51b5b9
        it exists Roles/COS definitions, then the server is
51b5b9
	configured to process the virtual attributes
51b5b9
        (nsslapd-ignore-virtual-attrs: off)
51b5b9
        design: https://www.port389.org/docs/389ds/design/vattr-automatic-toggle.html
51b5b9
51b5b9
relates: https://github.com/389ds/389-ds-base/issues/4678
51b5b9
51b5b9
Reviewed by: William Brown, Simon Pichugin, Mark Reynolds (Thanks !!)
51b5b9
51b5b9
Platforms tested: F34
51b5b9
---
51b5b9
 .../tests/suites/config/config_test.py        |  40 +++-
51b5b9
 dirsrvtests/tests/suites/cos/cos_test.py      |  94 ++++++--
51b5b9
 dirsrvtests/tests/suites/roles/basic_test.py  | 200 +++++++++++++++++-
51b5b9
 ldap/servers/plugins/roles/roles_cache.c      |   9 +
51b5b9
 ldap/servers/slapd/libglobs.c                 |   2 +-
51b5b9
 ldap/servers/slapd/main.c                     |   2 +
51b5b9
 ldap/servers/slapd/proto-slap.h               |   1 +
51b5b9
 ldap/servers/slapd/vattr.c                    | 127 +++++++++++
51b5b9
 src/lib389/lib389/idm/role.py                 |   4 +
51b5b9
 9 files changed, 455 insertions(+), 24 deletions(-)
51b5b9
51b5b9
diff --git a/dirsrvtests/tests/suites/config/config_test.py b/dirsrvtests/tests/suites/config/config_test.py
51b5b9
index 2ecff8f98..19232c87d 100644
51b5b9
--- a/dirsrvtests/tests/suites/config/config_test.py
51b5b9
+++ b/dirsrvtests/tests/suites/config/config_test.py
51b5b9
@@ -351,7 +351,7 @@ def test_ignore_virtual_attrs(topo):
51b5b9
     :setup: Standalone instance
51b5b9
     :steps:
51b5b9
          1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
51b5b9
-         2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF
51b5b9
+         2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
51b5b9
          3. Set the valid values i.e. on/ON and off/OFF for nsslapd-ignore-virtual-attrs
51b5b9
          4. Set invalid value for attribute nsslapd-ignore-virtual-attrs
51b5b9
          5. Set nsslapd-ignore-virtual-attrs=off
51b5b9
@@ -374,8 +374,8 @@ def test_ignore_virtual_attrs(topo):
51b5b9
     log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
51b5b9
     assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
51b5b9
 
51b5b9
-    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
51b5b9
-    assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "off"
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
51b5b9
+    assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
51b5b9
 
51b5b9
     log.info("Set the valid values i.e. on/ON and off/OFF for nsslapd-ignore-virtual-attrs")
51b5b9
     for attribute_value in ['on', 'off', 'ON', 'OFF']:
51b5b9
@@ -415,6 +415,40 @@ def test_ignore_virtual_attrs(topo):
51b5b9
     log.info("Test if virtual attribute i.e. postal code not shown while nsslapd-ignore-virtual-attrs: on")
51b5b9
     assert not test_user.present('postalcode', '117')
51b5b9
 
51b5b9
+def test_ignore_virtual_attrs_after_restart(topo):
51b5b9
+    """Test nsslapd-ignore-virtual-attrs configuration attribute
51b5b9
+       The attribute is ON by default. If it set to OFF, it keeps
51b5b9
+       its value on restart
51b5b9
+
51b5b9
+    :id: ac368649-4fda-473c-9ef8-e0c728b162af
51b5b9
+    :setup: Standalone instance
51b5b9
+    :steps:
51b5b9
+         1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
51b5b9
+         2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
51b5b9
+         3. Set nsslapd-ignore-virtual-attrs=off
51b5b9
+         4. restart the instance
51b5b9
+         5. Check the attribute nsslapd-ignore-virtual-attrs is OFF
51b5b9
+    :expectedresults:
51b5b9
+         1. This should be successful
51b5b9
+         2. This should be successful
51b5b9
+         3. This should be successful
51b5b9
+         4. This should be successful
51b5b9
+         5. This should be successful
51b5b9
+    """
51b5b9
+
51b5b9
+    log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
51b5b9
+    assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
51b5b9
+
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
51b5b9
+    assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
51b5b9
+
51b5b9
+    log.info("Set nsslapd-ignore-virtual-attrs = off")
51b5b9
+    topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'off')
51b5b9
+
51b5b9
+    topo.standalone.restart()
51b5b9
+
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
51b5b9
+    assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
51b5b9
 
51b5b9
 @pytest.mark.bz918694
51b5b9
 @pytest.mark.ds408
51b5b9
diff --git a/dirsrvtests/tests/suites/cos/cos_test.py b/dirsrvtests/tests/suites/cos/cos_test.py
51b5b9
index d6a498c73..d1f99f96f 100644
51b5b9
--- a/dirsrvtests/tests/suites/cos/cos_test.py
51b5b9
+++ b/dirsrvtests/tests/suites/cos/cos_test.py
51b5b9
@@ -6,6 +6,8 @@
51b5b9
 # See LICENSE for details.
51b5b9
 # --- END COPYRIGHT BLOCK ---
51b5b9
 
51b5b9
+import logging
51b5b9
+import time
51b5b9
 import pytest, os, ldap
51b5b9
 from lib389.cos import  CosClassicDefinition, CosClassicDefinitions, CosTemplate
51b5b9
 from lib389._constants import DEFAULT_SUFFIX
51b5b9
@@ -14,26 +16,37 @@ from lib389.idm.role import FilteredRoles
51b5b9
 from lib389.idm.nscontainer import nsContainer
51b5b9
 from lib389.idm.user import UserAccount
51b5b9
 
51b5b9
+logging.getLogger(__name__).setLevel(logging.INFO)
51b5b9
+log = logging.getLogger(__name__)
51b5b9
+
51b5b9
 pytestmark = pytest.mark.tier1
51b5b9
+@pytest.fixture(scope="function")
51b5b9
+def reset_ignore_vattr(topo, request):
51b5b9
+    default_ignore_vattr_value = topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs')
51b5b9
+    def fin():
51b5b9
+        topo.standalone.config.set('nsslapd-ignore-virtual-attrs', default_ignore_vattr_value)
51b5b9
 
51b5b9
-def test_positive(topo):
51b5b9
-    """
51b5b9
-        :id: a5a74235-597f-4fe8-8c38-826860927472
51b5b9
-        :setup: server
51b5b9
-        :steps:
51b5b9
-            1. Add filter role entry
51b5b9
-            2. Add ns container
51b5b9
-            3. Add cos template
51b5b9
-            4. Add CosClassic Definition
51b5b9
-            5. Cos entries should be added and searchable
51b5b9
-            6. employeeType attribute should be there in user entry as per the cos plugin property
51b5b9
-        :expectedresults:
51b5b9
-            1. Operation should success
51b5b9
-            2. Operation should success
51b5b9
-            3. Operation should success
51b5b9
-            4. Operation should success
51b5b9
-            5. Operation should success
51b5b9
-            6. Operation should success
51b5b9
+    request.addfinalizer(fin)
51b5b9
+
51b5b9
+def test_positive(topo, reset_ignore_vattr):
51b5b9
+    """CoS positive tests
51b5b9
+
51b5b9
+    :id: a5a74235-597f-4fe8-8c38-826860927472
51b5b9
+    :setup: server
51b5b9
+    :steps:
51b5b9
+        1. Add filter role entry
51b5b9
+        2. Add ns container
51b5b9
+        3. Add cos template
51b5b9
+        4. Add CosClassic Definition
51b5b9
+        5. Cos entries should be added and searchable
51b5b9
+        6. employeeType attribute should be there in user entry as per the cos plugin property
51b5b9
+    :expectedresults:
51b5b9
+        1. Operation should success
51b5b9
+        2. Operation should success
51b5b9
+        3. Operation should success
51b5b9
+        4. Operation should success
51b5b9
+        5. Operation should success
51b5b9
+        6. Operation should success
51b5b9
     """
51b5b9
     # Adding ns filter role
51b5b9
     roles = FilteredRoles(topo.standalone, DEFAULT_SUFFIX)
51b5b9
@@ -77,7 +90,52 @@ def test_positive(topo):
51b5b9
 
51b5b9
     #  CoS definition entry's cosSpecifier attribute specifies the employeeType attribute
51b5b9
     assert user.present('employeeType')
51b5b9
+    cosdef.delete()
51b5b9
+
51b5b9
+def test_vattr_on_cos_definition(topo, reset_ignore_vattr):
51b5b9
+    """Test nsslapd-ignore-virtual-attrs configuration attribute
51b5b9
+       The attribute is ON by default. If a cos definition is
51b5b9
+       added it is moved to OFF
51b5b9
+
51b5b9
+    :id: e7ef5254-386f-4362-bbb4-9409f3f51b08
51b5b9
+    :setup: Standalone instance
51b5b9
+    :steps:
51b5b9
+         1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
51b5b9
+         2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
51b5b9
+         3. Create a cos definition for employeeType
51b5b9
+         4. Check the value of nsslapd-ignore-virtual-attrs should be OFF (with a delay for postop processing)
51b5b9
+         5. Check a message "slapi_vattrspi_regattr - Because employeeType,.." in error logs
51b5b9
+    :expectedresults:
51b5b9
+         1. This should be successful
51b5b9
+         2. This should be successful
51b5b9
+         3. This should be successful
51b5b9
+         4. This should be successful
51b5b9
+         5. This should be successful
51b5b9
+    """
51b5b9
+
51b5b9
+    log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
51b5b9
+    assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
51b5b9
+
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
51b5b9
+    assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
51b5b9
+
51b5b9
+    # creating CosClassicDefinition
51b5b9
+    log.info("Create a cos definition")
51b5b9
+    properties = {'cosTemplateDn': 'cn=cosClassicGenerateEmployeeTypeUsingnsroleTemplates,{}'.format(DEFAULT_SUFFIX),
51b5b9
+                  'cosAttribute': 'employeeType',
51b5b9
+                  'cosSpecifier': 'nsrole',
51b5b9
+                  'cn': 'cosClassicGenerateEmployeeTypeUsingnsrole'}
51b5b9
+    cosdef = CosClassicDefinition(topo.standalone,'cn=cosClassicGenerateEmployeeTypeUsingnsrole,{}'.format(DEFAULT_SUFFIX))\
51b5b9
+        .create(properties=properties)
51b5b9
+
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
51b5b9
+    time.sleep(2)
51b5b9
+    assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
51b5b9
 
51b5b9
+    topo.standalone.stop()
51b5b9
+    assert topo.standalone.searchErrorsLog("slapi_vattrspi_regattr - Because employeeType is a new registered virtual attribute , nsslapd-ignore-virtual-attrs was set to \'off\'")
51b5b9
+    topo.standalone.start()
51b5b9
+    cosdef.delete()
51b5b9
 
51b5b9
 if __name__ == "__main__":
51b5b9
     CURRENT_FILE = os.path.realpath(__file__)
51b5b9
diff --git a/dirsrvtests/tests/suites/roles/basic_test.py b/dirsrvtests/tests/suites/roles/basic_test.py
51b5b9
index 47a531794..bec3aedfc 100644
51b5b9
--- a/dirsrvtests/tests/suites/roles/basic_test.py
51b5b9
+++ b/dirsrvtests/tests/suites/roles/basic_test.py
51b5b9
@@ -11,6 +11,8 @@
51b5b9
 Importing necessary Modules.
51b5b9
 """
51b5b9
 
51b5b9
+import logging
51b5b9
+import time
51b5b9
 import os
51b5b9
 import pytest
51b5b9
 
51b5b9
@@ -22,6 +24,9 @@ from lib389.topologies import topology_st as topo
51b5b9
 from lib389.idm.role import FilteredRoles, ManagedRoles, NestedRoles
51b5b9
 from lib389.idm.domain import Domain
51b5b9
 
51b5b9
+logging.getLogger(__name__).setLevel(logging.INFO)
51b5b9
+log = logging.getLogger(__name__)
51b5b9
+
51b5b9
 pytestmark = pytest.mark.tier1
51b5b9
 
51b5b9
 DNBASE = "o=acivattr,{}".format(DEFAULT_SUFFIX)
51b5b9
@@ -35,7 +40,7 @@ FILTERROLESALESROLE = "cn=FILTERROLESALESROLE,{}".format(DNBASE)
51b5b9
 FILTERROLEENGROLE = "cn=FILTERROLEENGROLE,{}".format(DNBASE)
51b5b9
 
51b5b9
 
51b5b9
-def test_filterrole(topo):
51b5b9
+def test_filterrole(topo, request):
51b5b9
     """Test Filter Role
51b5b9
 
51b5b9
     :id: 8ada4064-786b-11e8-8634-8c16451d917b
51b5b9
@@ -136,8 +141,20 @@ def test_filterrole(topo):
51b5b9
                   SALES_OU, DNBASE]:
51b5b9
         UserAccount(topo.standalone, dn_dn).delete()
51b5b9
 
51b5b9
+    def fin():
51b5b9
+        topo.standalone.restart()
51b5b9
+        try:
51b5b9
+            filtered_roles = FilteredRoles(topo.standalone, DEFAULT_SUFFIX)
51b5b9
+            for i in filtered_roles.list():
51b5b9
+                i.delete()
51b5b9
+        except:
51b5b9
+            pass
51b5b9
+        topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
51b5b9
+
51b5b9
+    request.addfinalizer(fin)
51b5b9
+
51b5b9
 
51b5b9
-def test_managedrole(topo):
51b5b9
+def test_managedrole(topo, request):
51b5b9
     """Test Managed Role
51b5b9
 
51b5b9
     :id: d52a9c00-3bf6-11e9-9b7b-8c16451d917b
51b5b9
@@ -209,6 +226,16 @@ def test_managedrole(topo):
51b5b9
     for i in roles.list():
51b5b9
         i.delete()
51b5b9
 
51b5b9
+    def fin():
51b5b9
+        topo.standalone.restart()
51b5b9
+        try:
51b5b9
+            role = ManagedRoles(topo.standalone, DEFAULT_SUFFIX).get('ROLE1')
51b5b9
+            role.delete()
51b5b9
+        except:
51b5b9
+            pass
51b5b9
+        topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
51b5b9
+
51b5b9
+    request.addfinalizer(fin)
51b5b9
 
51b5b9
 @pytest.fixture(scope="function")
51b5b9
 def _final(request, topo):
51b5b9
@@ -220,6 +247,7 @@ def _final(request, topo):
51b5b9
     def finofaci():
51b5b9
         """
51b5b9
         Removes and Restores ACIs and other users after the test.
51b5b9
+        And restore nsslapd-ignore-virtual-attrs to default
51b5b9
         """
51b5b9
         domain = Domain(topo.standalone, DEFAULT_SUFFIX)
51b5b9
         domain.remove_all('aci')
51b5b9
@@ -234,6 +262,8 @@ def _final(request, topo):
51b5b9
         for i in aci_list:
51b5b9
             domain.add("aci", i)
51b5b9
 
51b5b9
+        topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
51b5b9
+
51b5b9
     request.addfinalizer(finofaci)
51b5b9
 
51b5b9
 
51b5b9
@@ -296,6 +326,172 @@ def test_nestedrole(topo, _final):
51b5b9
     conn = users.get('test_user_3').bind(PW_DM)
51b5b9
     assert UserAccounts(conn, DEFAULT_SUFFIX).list()
51b5b9
 
51b5b9
+def test_vattr_on_filtered_role(topo, request):
51b5b9
+    """Test nsslapd-ignore-virtual-attrs configuration attribute
51b5b9
+       The attribute is ON by default. If a filtered role is
51b5b9
+       added it is moved to OFF
51b5b9
+
51b5b9
+    :id: 88b3ad3c-f39a-4eb7-a8c9-07c685f11908
51b5b9
+    :setup: Standalone instance
51b5b9
+    :steps:
51b5b9
+         1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
51b5b9
+         2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
51b5b9
+         3. Create a filtered role
51b5b9
+         4. Check the value of nsslapd-ignore-virtual-attrs should be OFF
51b5b9
+         5. Check a message "roles_cache_trigger_update_role - Because of virtual attribute.." in error logs
51b5b9
+    :expectedresults:
51b5b9
+         1. This should be successful
51b5b9
+         2. This should be successful
51b5b9
+         3. This should be successful
51b5b9
+         4. This should be successful
51b5b9
+         5. This should be successful
51b5b9
+    """
51b5b9
+
51b5b9
+    log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
51b5b9
+    assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
51b5b9
+
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
51b5b9
+    assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
51b5b9
+
51b5b9
+    log.info("Create a filtered role")
51b5b9
+    try:
51b5b9
+        Organization(topo.standalone).create(properties={"o": "acivattr"}, basedn=DEFAULT_SUFFIX)
51b5b9
+    except:
51b5b9
+        pass
51b5b9
+    roles = FilteredRoles(topo.standalone, DNBASE)
51b5b9
+    roles.create(properties={'cn': 'FILTERROLEENGROLE', 'nsRoleFilter': 'cn=eng*'})
51b5b9
+
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
51b5b9
+    assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
51b5b9
+
51b5b9
+    topo.standalone.stop()
51b5b9
+    assert topo.standalone.searchErrorsLog("roles_cache_trigger_update_role - Because of virtual attribute definition \(role\), nsslapd-ignore-virtual-attrs was set to \'off\'")
51b5b9
+
51b5b9
+    def fin():
51b5b9
+        topo.standalone.restart()
51b5b9
+        try:
51b5b9
+            filtered_roles = FilteredRoles(topo.standalone, DEFAULT_SUFFIX)
51b5b9
+            for i in filtered_roles.list():
51b5b9
+                i.delete()
51b5b9
+        except:
51b5b9
+            pass
51b5b9
+        topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
51b5b9
+
51b5b9
+    request.addfinalizer(fin)
51b5b9
+
51b5b9
+def test_vattr_on_filtered_role_restart(topo, request):
51b5b9
+    """Test nsslapd-ignore-virtual-attrs configuration attribute
51b5b9
+    If it exists a filtered role definition at restart then
51b5b9
+    nsslapd-ignore-virtual-attrs should be set to 'off'
51b5b9
+
51b5b9
+    :id: 972183f7-d18f-40e0-94ab-580e7b7d78d0
51b5b9
+    :setup: Standalone instance
51b5b9
+    :steps:
51b5b9
+         1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
51b5b9
+         2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
51b5b9
+         3. Create a filtered role
51b5b9
+         4. Check the value of nsslapd-ignore-virtual-attrs should be OFF
51b5b9
+         5. restart the instance
51b5b9
+         6. Check the presence of virtual attribute is detected
51b5b9
+         7. Check the value of nsslapd-ignore-virtual-attrs should be OFF
51b5b9
+    :expectedresults:
51b5b9
+         1. This should be successful
51b5b9
+         2. This should be successful
51b5b9
+         3. This should be successful
51b5b9
+         4. This should be successful
51b5b9
+         5. This should be successful
51b5b9
+         6. This should be successful
51b5b9
+         7. This should be successful
51b5b9
+    """
51b5b9
+
51b5b9
+    log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
51b5b9
+    assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
51b5b9
+
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
51b5b9
+    assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
51b5b9
+
51b5b9
+    log.info("Create a filtered role")
51b5b9
+    try:
51b5b9
+        Organization(topo.standalone).create(properties={"o": "acivattr"}, basedn=DEFAULT_SUFFIX)
51b5b9
+    except:
51b5b9
+        pass
51b5b9
+    roles = FilteredRoles(topo.standalone, DNBASE)
51b5b9
+    roles.create(properties={'cn': 'FILTERROLEENGROLE', 'nsRoleFilter': 'cn=eng*'})
51b5b9
+
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
51b5b9
+    assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
51b5b9
+
51b5b9
+    
51b5b9
+    log.info("Check the virtual attribute definition is found (after a required delay)")
51b5b9
+    topo.standalone.restart()
51b5b9
+    time.sleep(5)
51b5b9
+    assert topo.standalone.searchErrorsLog("Found a role/cos definition in")
51b5b9
+    assert topo.standalone.searchErrorsLog("roles_cache_trigger_update_role - Because of virtual attribute definition \(role\), nsslapd-ignore-virtual-attrs was set to \'off\'")
51b5b9
+
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
51b5b9
+    assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
51b5b9
+
51b5b9
+    def fin():
51b5b9
+        topo.standalone.restart()
51b5b9
+        try:
51b5b9
+            filtered_roles = FilteredRoles(topo.standalone, DEFAULT_SUFFIX)
51b5b9
+            for i in filtered_roles.list():
51b5b9
+                i.delete()
51b5b9
+        except:
51b5b9
+            pass
51b5b9
+        topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
51b5b9
+
51b5b9
+    request.addfinalizer(fin)
51b5b9
+
51b5b9
+
51b5b9
+def test_vattr_on_managed_role(topo, request):
51b5b9
+    """Test nsslapd-ignore-virtual-attrs configuration attribute
51b5b9
+       The attribute is ON by default. If a managed role is
51b5b9
+       added it is moved to OFF
51b5b9
+
51b5b9
+    :id: 664b722d-c1ea-41e4-8f6c-f9c87a212346
51b5b9
+    :setup: Standalone instance
51b5b9
+    :steps:
51b5b9
+         1. Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config
51b5b9
+         2. Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON
51b5b9
+         3. Create a managed role
51b5b9
+         4. Check the value of nsslapd-ignore-virtual-attrs should be OFF
51b5b9
+         5. Check a message "roles_cache_trigger_update_role - Because of virtual attribute.." in error logs
51b5b9
+    :expectedresults:
51b5b9
+         1. This should be successful
51b5b9
+         2. This should be successful
51b5b9
+         3. This should be successful
51b5b9
+         4. This should be successful
51b5b9
+         5. This should be successful
51b5b9
+    """
51b5b9
+
51b5b9
+    log.info("Check the attribute nsslapd-ignore-virtual-attrs is present in cn=config")
51b5b9
+    assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs')
51b5b9
+
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be ON")
51b5b9
+    assert topo.standalone.config.get_attr_val_utf8('nsslapd-ignore-virtual-attrs') == "on"
51b5b9
+
51b5b9
+    log.info("Create a managed role")
51b5b9
+    roles = ManagedRoles(topo.standalone, DEFAULT_SUFFIX)
51b5b9
+    role = roles.create(properties={"cn": 'ROLE1'})
51b5b9
+
51b5b9
+    log.info("Check the default value of attribute nsslapd-ignore-virtual-attrs should be OFF")
51b5b9
+    assert topo.standalone.config.present('nsslapd-ignore-virtual-attrs', 'off')
51b5b9
+
51b5b9
+    topo.standalone.stop()
51b5b9
+    assert topo.standalone.searchErrorsLog("roles_cache_trigger_update_role - Because of virtual attribute definition \(role\), nsslapd-ignore-virtual-attrs was set to \'off\'")
51b5b9
+
51b5b9
+    def fin():
51b5b9
+        topo.standalone.restart()
51b5b9
+        try:
51b5b9
+            filtered_roles = ManagedRoles(topo.standalone, DEFAULT_SUFFIX)
51b5b9
+            for i in filtered_roles.list():
51b5b9
+                i.delete()
51b5b9
+        except:
51b5b9
+            pass
51b5b9
+        topo.standalone.config.set('nsslapd-ignore-virtual-attrs', 'on')
51b5b9
+
51b5b9
+    request.addfinalizer(fin)
51b5b9
 
51b5b9
 if __name__ == "__main__":
51b5b9
     CURRENT_FILE = os.path.realpath(__file__)
51b5b9
diff --git a/ldap/servers/plugins/roles/roles_cache.c b/ldap/servers/plugins/roles/roles_cache.c
51b5b9
index 3d076a4cb..cd00e0aba 100644
51b5b9
--- a/ldap/servers/plugins/roles/roles_cache.c
51b5b9
+++ b/ldap/servers/plugins/roles/roles_cache.c
51b5b9
@@ -530,6 +530,15 @@ roles_cache_trigger_update_role(char *dn, Slapi_Entry *roles_entry, Slapi_DN *be
51b5b9
     }
51b5b9
 
51b5b9
     slapi_rwlock_unlock(global_lock);
51b5b9
+    {
51b5b9
+        /* A role definition has been updated, enable vattr handling */
51b5b9
+        char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
51b5b9
+        errorbuf[0] = '\0';
51b5b9
+        config_set_ignore_vattrs(CONFIG_IGNORE_VATTRS, "off", errorbuf, 1);
51b5b9
+        slapi_log_err(SLAPI_LOG_INFO,
51b5b9
+                      "roles_cache_trigger_update_role",
51b5b9
+                      "Because of virtual attribute definition (role), %s was set to 'off'\n", CONFIG_IGNORE_VATTRS);
51b5b9
+    }
51b5b9
 
51b5b9
     slapi_log_err(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_trigger_update_role: %p \n", roles_list);
51b5b9
 }
51b5b9
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
51b5b9
index 2ea4cd760..f6dacce30 100644
51b5b9
--- a/ldap/servers/slapd/libglobs.c
51b5b9
+++ b/ldap/servers/slapd/libglobs.c
51b5b9
@@ -1803,7 +1803,7 @@ FrontendConfig_init(void)
51b5b9
     init_ndn_cache_enabled = cfg->ndn_cache_enabled = LDAP_ON;
51b5b9
     cfg->ndn_cache_max_size = SLAPD_DEFAULT_NDN_SIZE;
51b5b9
     init_sasl_mapping_fallback = cfg->sasl_mapping_fallback = LDAP_OFF;
51b5b9
-    init_ignore_vattrs = cfg->ignore_vattrs = LDAP_OFF;
51b5b9
+    init_ignore_vattrs = cfg->ignore_vattrs = LDAP_ON;
51b5b9
     cfg->sasl_max_bufsize = SLAPD_DEFAULT_SASL_MAXBUFSIZE;
51b5b9
     cfg->unhashed_pw_switch = SLAPD_DEFAULT_UNHASHED_PW_SWITCH;
51b5b9
     init_return_orig_type = cfg->return_orig_type = LDAP_OFF;
51b5b9
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
51b5b9
index 4931a4ca4..61ed40b7d 100644
51b5b9
--- a/ldap/servers/slapd/main.c
51b5b9
+++ b/ldap/servers/slapd/main.c
51b5b9
@@ -1042,6 +1042,8 @@ main(int argc, char **argv)
51b5b9
         eq_start(); /* must be done after plugins started - DEPRECATED */
51b5b9
         eq_start_rel(); /* must be done after plugins started */
51b5b9
 
51b5b9
+        vattr_check(); /* Check if it exists virtual attribute definitions */
51b5b9
+
51b5b9
 #ifdef HPUX10
51b5b9
         /* HPUX linker voodoo */
51b5b9
         if (collation_init == NULL) {
51b5b9
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
51b5b9
index c143f3772..442a621aa 100644
51b5b9
--- a/ldap/servers/slapd/proto-slap.h
51b5b9
+++ b/ldap/servers/slapd/proto-slap.h
51b5b9
@@ -1462,6 +1462,7 @@ void subentry_create_filter(Slapi_Filter **filter);
51b5b9
  */
51b5b9
 void vattr_init(void);
51b5b9
 void vattr_cleanup(void);
51b5b9
+void vattr_check(void);
51b5b9
 
51b5b9
 /*
51b5b9
  * slapd_plhash.c - supplement to NSPR plhash
51b5b9
diff --git a/ldap/servers/slapd/vattr.c b/ldap/servers/slapd/vattr.c
51b5b9
index 09dab6ecf..24750a57c 100644
51b5b9
--- a/ldap/servers/slapd/vattr.c
51b5b9
+++ b/ldap/servers/slapd/vattr.c
51b5b9
@@ -64,6 +64,10 @@
51b5b9
 #define SOURCEFILE "vattr.c"
51b5b9
 static char *sourcefile = SOURCEFILE;
51b5b9
 
51b5b9
+/* stolen from roles_cache.h, must remain in sync */
51b5b9
+#define NSROLEATTR "nsRole"
51b5b9
+static Slapi_Eq_Context vattr_check_ctx = {0};
51b5b9
+
51b5b9
 /* Define only for module test code */
51b5b9
 /* #define VATTR_TEST_CODE */
51b5b9
 
51b5b9
@@ -130,6 +134,112 @@ vattr_cleanup()
51b5b9
 {
51b5b9
     /* We need to free and remove anything that was inserted first */
51b5b9
     vattr_map_destroy();
51b5b9
+    slapi_eq_cancel_rel(vattr_check_ctx);
51b5b9
+}
51b5b9
+
51b5b9
+static void
51b5b9
+vattr_check_thread(void *arg)
51b5b9
+{
51b5b9
+    Slapi_Backend *be = NULL;
51b5b9
+    char *cookie = NULL;
51b5b9
+    Slapi_DN *base_sdn = NULL;
51b5b9
+    Slapi_PBlock *search_pb = NULL;
51b5b9
+    Slapi_Entry **entries = NULL;
51b5b9
+    int32_t rc;
51b5b9
+    int32_t check_suffix; /* used to skip suffixes in ignored_backend */
51b5b9
+    PRBool exist_vattr_definition = PR_FALSE;
51b5b9
+    char *ignored_backend[5] = {"cn=config", "cn=schema", "cn=monitor", "cn=changelog", NULL}; /* suffixes to ignore */
51b5b9
+    char *suffix;
51b5b9
+    int ignore_vattrs;
51b5b9
+
51b5b9
+    ignore_vattrs = config_get_ignore_vattrs();
51b5b9
+
51b5b9
+    if (!ignore_vattrs) {
51b5b9
+        /* Nothing to do more, we are already evaluating virtual attribute */
51b5b9
+        return;
51b5b9
+    }
51b5b9
+
51b5b9
+    search_pb = slapi_pblock_new();
51b5b9
+    be = slapi_get_first_backend(&cookie);
51b5b9
+    while (be && !exist_vattr_definition && !slapi_is_shutting_down()) {
51b5b9
+        base_sdn = (Slapi_DN *) slapi_be_getsuffix(be, 0);
51b5b9
+        suffix = (char *) slapi_sdn_get_dn(base_sdn);
51b5b9
+
51b5b9
+        if (suffix) {
51b5b9
+            /* First check that we need to check that suffix */
51b5b9
+            check_suffix = 1;
51b5b9
+            for (size_t i = 0; ignored_backend[i]; i++) {
51b5b9
+                if (strcasecmp(suffix, ignored_backend[i]) == 0) {
51b5b9
+                    check_suffix = 0;
51b5b9
+                    break;
51b5b9
+                }
51b5b9
+            }
51b5b9
+
51b5b9
+            /* search for a role or cos definition */
51b5b9
+            if (check_suffix) {
51b5b9
+                slapi_search_internal_set_pb(search_pb, slapi_sdn_get_dn(base_sdn),
51b5b9
+                        LDAP_SCOPE_SUBTREE, "(&(objectclass=ldapsubentry)(|(objectclass=nsRoleDefinition)(objectclass=cosSuperDefinition)))",
51b5b9
+                        NULL, 0, NULL, NULL, (void *) plugin_get_default_component_id(), 0);
51b5b9
+                slapi_search_internal_pb(search_pb);
51b5b9
+                slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
51b5b9
+
51b5b9
+                if (rc == LDAP_SUCCESS) {
51b5b9
+                    slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
51b5b9
+                    if (entries && entries[0]) {
51b5b9
+                        /* it exists at least a cos or role definition */
51b5b9
+                        exist_vattr_definition = PR_TRUE;
51b5b9
+                        slapi_log_err(SLAPI_LOG_INFO,
51b5b9
+                                "vattr_check_thread",
51b5b9
+                                "Found a role/cos definition in %s\n", slapi_entry_get_dn(entries[0]));
51b5b9
+                    } else {
51b5b9
+                        slapi_log_err(SLAPI_LOG_INFO,
51b5b9
+                                "vattr_check_thread",
51b5b9
+                                "No role/cos definition in %s\n", slapi_sdn_get_dn(base_sdn));
51b5b9
+                    }
51b5b9
+                }
51b5b9
+                slapi_free_search_results_internal(search_pb);
51b5b9
+            } /* check_suffix */
51b5b9
+        } /* suffix */
51b5b9
+        be = (backend *) slapi_get_next_backend(cookie);
51b5b9
+    }
51b5b9
+    slapi_pblock_destroy(search_pb);
51b5b9
+    slapi_ch_free_string(&cookie);
51b5b9
+
51b5b9
+    /* Now if a virtual attribute is defined, then CONFIG_IGNORE_VATTRS -> off */
51b5b9
+    if (exist_vattr_definition) {
51b5b9
+        char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
51b5b9
+        errorbuf[0] = '\0';
51b5b9
+        config_set_ignore_vattrs(CONFIG_IGNORE_VATTRS, "off", errorbuf, 1);
51b5b9
+        slapi_log_err(SLAPI_LOG_INFO,
51b5b9
+                      "vattr_check_thread",
51b5b9
+                      "Because of virtual attribute definition, %s was set to 'off'\n", CONFIG_IGNORE_VATTRS);
51b5b9
+    }
51b5b9
+}
51b5b9
+static void
51b5b9
+vattr_check_schedule_once(time_t when __attribute__((unused)), void *arg)
51b5b9
+{
51b5b9
+    if (PR_CreateThread(PR_USER_THREAD,
51b5b9
+                        vattr_check_thread,
51b5b9
+                        (void *) arg,
51b5b9
+                        PR_PRIORITY_NORMAL,
51b5b9
+                        PR_GLOBAL_THREAD,
51b5b9
+                        PR_UNJOINABLE_THREAD,
51b5b9
+                        SLAPD_DEFAULT_THREAD_STACKSIZE) == NULL) {
51b5b9
+        slapi_log_err(SLAPI_LOG_ERR,
51b5b9
+                      "vattr_check_schedule_once",
51b5b9
+                      "Fails to check if %s needs to be toggled to FALSE\n", CONFIG_IGNORE_VATTRS);
51b5b9
+    }
51b5b9
+}
51b5b9
+#define VATTR_CHECK_DELAY 3
51b5b9
+void
51b5b9
+vattr_check()
51b5b9
+{
51b5b9
+    /* Schedule running a callback that will create a thread
51b5b9
+     * but make sure it is called a first thing when event loop is created */
51b5b9
+    time_t now;
51b5b9
+
51b5b9
+    now = slapi_current_rel_time_t();
51b5b9
+    vattr_check_ctx = slapi_eq_once_rel(vattr_check_schedule_once, NULL, now + VATTR_CHECK_DELAY);
51b5b9
 }
51b5b9
 
51b5b9
 /* The public interface functions start here */
51b5b9
@@ -1631,6 +1741,9 @@ slapi_vattrspi_regattr(vattr_sp_handle *h, char *type_name_to_register, char *DN
51b5b9
     char *type_to_add;
51b5b9
     int free_type_to_add = 0;
51b5b9
     Slapi_DN original_dn;
51b5b9
+    int ignore_vattrs;
51b5b9
+
51b5b9
+    ignore_vattrs = config_get_ignore_vattrs();
51b5b9
 
51b5b9
     slapi_sdn_init(&original_dn);
51b5b9
 
51b5b9
@@ -1676,6 +1789,20 @@ slapi_vattrspi_regattr(vattr_sp_handle *h, char *type_name_to_register, char *DN
51b5b9
     if (free_type_to_add) {
51b5b9
         slapi_ch_free((void **)&type_to_add);
51b5b9
     }
51b5b9
+    if (ignore_vattrs && strcasecmp(type_name_to_register, NSROLEATTR)) {
51b5b9
+        /* A new virtual attribute is registered.
51b5b9
+         * This new vattr being *different* than the default roles vattr 'nsRole'
51b5b9
+         * It is time to allow vattr lookup
51b5b9
+         */
51b5b9
+        char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
51b5b9
+        errorbuf[0] = '\0';
51b5b9
+        config_set_ignore_vattrs(CONFIG_IGNORE_VATTRS, "off", errorbuf, 1);
51b5b9
+        slapi_log_err(SLAPI_LOG_INFO,
51b5b9
+                      "slapi_vattrspi_regattr",
51b5b9
+                      "Because %s is a new registered virtual attribute , %s was set to 'off'\n",
51b5b9
+                      type_name_to_register,
51b5b9
+                      CONFIG_IGNORE_VATTRS);
51b5b9
+    }
51b5b9
 
51b5b9
     return ret;
51b5b9
 }
51b5b9
diff --git a/src/lib389/lib389/idm/role.py b/src/lib389/lib389/idm/role.py
51b5b9
index fe91aab6f..9a2bff3d6 100644
51b5b9
--- a/src/lib389/lib389/idm/role.py
51b5b9
+++ b/src/lib389/lib389/idm/role.py
51b5b9
@@ -252,6 +252,8 @@ class FilteredRole(Role):
51b5b9
         self._rdn_attribute = 'cn'
51b5b9
         self._create_objectclasses = ['nsComplexRoleDefinition', 'nsFilteredRoleDefinition']
51b5b9
 
51b5b9
+        self._protected = False
51b5b9
+
51b5b9
 
51b5b9
 
51b5b9
 class FilteredRoles(Roles):
51b5b9
@@ -285,6 +287,7 @@ class ManagedRole(Role):
51b5b9
         self._rdn_attribute = 'cn'
51b5b9
         self._create_objectclasses = ['nsSimpleRoleDefinition', 'nsManagedRoleDefinition']
51b5b9
 
51b5b9
+        self._protected = False
51b5b9
 
51b5b9
 class ManagedRoles(Roles):
51b5b9
     """DSLdapObjects that represents all Managed Roles entries
51b5b9
@@ -320,6 +323,7 @@ class NestedRole(Role):
51b5b9
         self._rdn_attribute = 'cn'
51b5b9
         self._create_objectclasses = ['nsComplexRoleDefinition', 'nsNestedRoleDefinition']
51b5b9
 
51b5b9
+        self._protected = False
51b5b9
 
51b5b9
 class NestedRoles(Roles):
51b5b9
     """DSLdapObjects that represents all NestedRoles entries in suffix.
51b5b9
-- 
51b5b9
2.31.1
51b5b9