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

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