|
|
26521d |
From 2a181763d0cff5f31dc18f3e71f79dd815906c09 Mon Sep 17 00:00:00 2001
|
|
|
26521d |
From: Mark Reynolds <mreynolds@redhat.com>
|
|
|
26521d |
Date: Fri, 22 Feb 2019 13:46:48 -0500
|
|
|
26521d |
Subject: [PATCH] Ticket 50238 - Failed modrdn can corrupt entry cache
|
|
|
26521d |
|
|
|
26521d |
Bug Description: Under certain conditions (found under IPA) when a backend
|
|
|
26521d |
transaction plugin fails and causes a modrdn operation to
|
|
|
26521d |
fail the entry cache no longer contains the original/pre
|
|
|
26521d |
entry, but instead it has the post modrdn'ed entry with
|
|
|
26521d |
the original entry's ID
|
|
|
26521d |
|
|
|
26521d |
Fix Description: Upon failure, if the post entry is in the cache, then swap
|
|
|
26521d |
it out with the original entry.
|
|
|
26521d |
|
|
|
26521d |
https://pagure.io/389-ds-base/issue/50238
|
|
|
26521d |
|
|
|
26521d |
Reviewed by: firstyear, spichugi, & tboardaz (Thanks!!!)
|
|
|
26521d |
---
|
|
|
26521d |
dirsrvtests/tests/suites/betxns/betxn_test.py | 57 +++++++++++++++++++
|
|
|
26521d |
ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 16 ++++--
|
|
|
26521d |
2 files changed, 68 insertions(+), 5 deletions(-)
|
|
|
26521d |
|
|
|
26521d |
diff --git a/dirsrvtests/tests/suites/betxns/betxn_test.py b/dirsrvtests/tests/suites/betxns/betxn_test.py
|
|
|
26521d |
index 175496495..48181a9ea 100644
|
|
|
26521d |
--- a/dirsrvtests/tests/suites/betxns/betxn_test.py
|
|
|
26521d |
+++ b/dirsrvtests/tests/suites/betxns/betxn_test.py
|
|
|
26521d |
@@ -8,6 +8,7 @@
|
|
|
26521d |
#
|
|
|
26521d |
import pytest
|
|
|
26521d |
import six
|
|
|
26521d |
+import ldap
|
|
|
26521d |
from lib389.tasks import *
|
|
|
26521d |
from lib389.utils import *
|
|
|
26521d |
from lib389.topologies import topology_st
|
|
|
26521d |
@@ -248,6 +249,62 @@ def test_betxn_memberof(topology_st, dynamic_plugins):
|
|
|
26521d |
log.info('test_betxn_memberof: PASSED')
|
|
|
26521d |
|
|
|
26521d |
|
|
|
26521d |
+def test_betxn_modrdn_memberof(topology_st):
|
|
|
26521d |
+ """Test modrdn operartions and memberOf
|
|
|
26521d |
+
|
|
|
26521d |
+ :id: 70d0b96e-b693-4bf7-bbf5-102a66ac5994
|
|
|
26521d |
+
|
|
|
26521d |
+ :setup: Standalone instance
|
|
|
26521d |
+
|
|
|
26521d |
+ :steps: 1. Enable and configure memberOf plugin
|
|
|
26521d |
+ 2. Set memberofgroupattr="member" and memberofAutoAddOC="nsContainer"
|
|
|
26521d |
+ 3. Create group and user outside of memberOf plugin scope
|
|
|
26521d |
+ 4. Do modrdn to move group into scope
|
|
|
26521d |
+ 5. Do modrdn to move group into scope (again)
|
|
|
26521d |
+
|
|
|
26521d |
+ :expectedresults:
|
|
|
26521d |
+ 1. memberOf plugin plugin should be ON
|
|
|
26521d |
+ 2. Set memberofgroupattr="member" and memberofAutoAddOC="nsContainer" should PASS
|
|
|
26521d |
+ 3. Creating group and user should PASS
|
|
|
26521d |
+ 4. Modrdn should fail with objectclass violation
|
|
|
26521d |
+ 5. Second modrdn should also fail with objectclass violation
|
|
|
26521d |
+ """
|
|
|
26521d |
+
|
|
|
26521d |
+ peoplebase = 'ou=people,%s' % DEFAULT_SUFFIX
|
|
|
26521d |
+ memberof = MemberOfPlugin(topology_st.standalone)
|
|
|
26521d |
+ memberof.enable()
|
|
|
26521d |
+ memberof.set_autoaddoc('nsContainer') # Bad OC
|
|
|
26521d |
+ memberof.set('memberOfEntryScope', peoplebase)
|
|
|
26521d |
+ memberof.set('memberOfAllBackends', 'on')
|
|
|
26521d |
+ topology_st.standalone.restart()
|
|
|
26521d |
+
|
|
|
26521d |
+ groups = Groups(topology_st.standalone, DEFAULT_SUFFIX)
|
|
|
26521d |
+ group = groups.create(properties={
|
|
|
26521d |
+ 'cn': 'group',
|
|
|
26521d |
+ })
|
|
|
26521d |
+
|
|
|
26521d |
+ # Create user and add it to group
|
|
|
26521d |
+ users = UserAccounts(topology_st.standalone, basedn=DEFAULT_SUFFIX)
|
|
|
26521d |
+ user = users.create(properties=TEST_USER_PROPERTIES)
|
|
|
26521d |
+ if not ds_is_older('1.3.7'):
|
|
|
26521d |
+ user.remove('objectClass', 'nsMemberOf')
|
|
|
26521d |
+
|
|
|
26521d |
+ group.add_member(user.dn)
|
|
|
26521d |
+
|
|
|
26521d |
+ # Attempt modrdn that should fail, but the original entry should stay in the cache
|
|
|
26521d |
+ with pytest.raises(ldap.OBJECTCLASS_VIOLATION):
|
|
|
26521d |
+ group.rename('cn=group_to_people', newsuperior=peoplebase)
|
|
|
26521d |
+
|
|
|
26521d |
+ # Should fail, but not with NO_SUCH_OBJECT as the original entry should still be in the cache
|
|
|
26521d |
+ with pytest.raises(ldap.OBJECTCLASS_VIOLATION):
|
|
|
26521d |
+ group.rename('cn=group_to_people', newsuperior=peoplebase)
|
|
|
26521d |
+
|
|
|
26521d |
+ #
|
|
|
26521d |
+ # Done
|
|
|
26521d |
+ #
|
|
|
26521d |
+ log.info('test_betxn_modrdn_memberof: PASSED')
|
|
|
26521d |
+
|
|
|
26521d |
+
|
|
|
26521d |
if __name__ == '__main__':
|
|
|
26521d |
# Run isolated
|
|
|
26521d |
# -s for DEBUG mode
|
|
|
26521d |
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
|
|
|
26521d |
index 684b040b8..e4d0337d4 100644
|
|
|
26521d |
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
|
|
|
26521d |
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
|
|
|
26521d |
@@ -1411,14 +1411,20 @@ common_return:
|
|
|
26521d |
"operation failed, the target entry is cleared from dncache (%s)\n", slapi_entry_get_dn(ec->ep_entry));
|
|
|
26521d |
CACHE_REMOVE(&inst->inst_dncache, bdn);
|
|
|
26521d |
CACHE_RETURN(&inst->inst_dncache, &bdn;;
|
|
|
26521d |
+ /*
|
|
|
26521d |
+ * If the new/invalid entry (ec) is in the cache, that means we need to
|
|
|
26521d |
+ * swap it out with the original entry (e) --> to undo the swap that
|
|
|
26521d |
+ * modrdn_rename_entry_update_indexes() did.
|
|
|
26521d |
+ */
|
|
|
26521d |
+ if (cache_is_in_cache(&inst->inst_cache, ec)) {
|
|
|
26521d |
+ if (cache_replace(&inst->inst_cache, ec, e) != 0) {
|
|
|
26521d |
+ slapi_log_err(SLAPI_LOG_ALERT, "ldbm_back_modrdn",
|
|
|
26521d |
+ "failed to replace cache entry after error\n");
|
|
|
26521d |
+ }
|
|
|
26521d |
+ }
|
|
|
26521d |
}
|
|
|
26521d |
|
|
|
26521d |
- /* remove the new entry from the cache if the op failed -
|
|
|
26521d |
- otherwise, leave it in */
|
|
|
26521d |
if (ec && inst) {
|
|
|
26521d |
- if (retval && cache_is_in_cache(&inst->inst_cache, ec)) {
|
|
|
26521d |
- CACHE_REMOVE(&inst->inst_cache, ec);
|
|
|
26521d |
- }
|
|
|
26521d |
CACHE_RETURN(&inst->inst_cache, &ec);
|
|
|
26521d |
}
|
|
|
26521d |
ec = NULL;
|
|
|
26521d |
--
|
|
|
26521d |
2.17.2
|
|
|
26521d |
|