Skip to content
Commits on Source (33)
  • Mark Reynolds's avatar
    Ticket 50165 - Fix issues with dscreate · 0036226b
    Mark Reynolds authored
    Bug Description:  The install would fail under these two conditions:
    
                       [1]  You do not specfiy a secure port, even if not using TLS
                       [2]  The suffix has a space after a comma.
    
    Fix Description:  If the secure port is not specified set it to the default,
                      and normalize the suffix DN
    
    https://pagure.io/389-ds-base/issue/50165
    
    Reviewed by: ?
    0036226b
  • Thierry Bordaz's avatar
    Ticket 50177 - import task should not be deleted too rapidely after import... · 98bfccc8
    Thierry Bordaz authored
    Ticket 50177 - import task should not be deleted too rapidely after import finishes to be able to query the status
    
    Bug Description:
    	scripts that create online import and export tasks do not define a Time To Life of the tasks.
    	As a consequence the task entry is cleared 2min (default value) after task completion.
    	This is too rapid and some admin scripts may miss the final task status.
    
    Fix Description:
    	The fix is to keep the entry of completed online import and export tasks for 1 day.
    	It also allows defines a default TTL to 1h (instead of 2min)
    
    https://pagure.io/389-ds-base/issue/50177
    
    Reviewed by: Mark Reynolds
    
    Platforms tested: F27
    
    Flag Day: no
    
    Doc impact: no
    98bfccc8
  • Thierry Bordaz's avatar
    Ticket 49658 - In replicated topology a single-valued attribute can diverge · 70cac1b1
    Thierry Bordaz authored
    Bug Description:
    	When deleting a specific value of a single valued attribute,
    	the deleted value can be erronously resurrected.
    
    Fix Description:
    	This second fix is a rewrite of entry state resolution.
    	The original function (resolve_attribute_state_single_valued) implemented
    	a main algorythm but it was heavily merged with resolution of specific cases.
    	It was too difficult to make the function understandable and preserving
    	the handling of the specific cases.
    	The risk of that rewrite fix is that I can not guarantee it fully covers
    	the set of specific cases
    
    https://pagure.io/389-ds-base/issue/49658
    
    Reviewed by: William Brown (Thanks !!)
    
    Platforms tested: F27
    
    Flag Day: no
    
    Doc impact: no
    70cac1b1
  • Thierry Bordaz's avatar
    Ticket 49873 - Contention on virtual attribute lookup · 6f87fab4
    Thierry Bordaz authored
    Bug Description:
    	During lookup of the virtual attribute table (filter evaluation and returned attribute)
    	the lock is acquired many times in read. For example it is acquired for each targetfilter aci and for
    	each evaluated entry.
    	Unfortunately RW lock is expensive and appears frequently on pstacks.
    	The lock exists because the table can be updated but update is very rare (addition of a new service provider).
    	So it slows down general proceeding for exceptional events.
    
    Fix Description:
    	The fix is to acquire/release the read lock at the operation level and set a per-cpu flag, so that later lookup
    	would just check the flag.
    
    https://pagure.io/389-ds-base/issue/49873
    
    Reviewed by: Ludwig Krispenz, William Brown (thanks !!)
    
    Platforms tested: F27
    
    Flag Day: no
    
    Doc impact: no
    6f87fab4
  • Mark Reynolds's avatar
    Ticket 50155 - password history check has no way to just check the current password · ba02f5a6
    Mark Reynolds authored
    Description:  Currently if you set passwordinhistory 1, it checks the last
                  recorded password and the current password.  To get it to just
                  check the current password we need to allow "0" in passwordinhistory.
                  Then only check the current password, and not the entry's
                  passwordHistory attributes (if any).
    
                  Also added new "rebind" function to Accounts class to "rebind"
                  on the current connection.
    
    https://pagure.io/389-ds-base/issue/50155
    
    Reviewed by: firstyear & spichugi (Thanks!!)
    ba02f5a6
  • William Brown's avatar
    Ticket 50151 - lib389 support cli add/replace/delete on objects · f19f2793
    William Brown authored
    Bug Description: We need a generic way to add/replace/delete on
    objects, that is not ldif. Ldif is wildly inaccessible and hard
    to use.
    
    Fix Description: Add a "modify" generic to cli_base, that is
    used by user. It supports a syntax of:
    
    modify <selector> <add|replace|delete>:<attr>:<value>
    
    An example is:
    
    ... user modify demo_user add:objectclass:nsMemberOf
    
    These can have many modifications in a single transaction:
    
    user modify demo_user add:objectclass:nsMemberOf add:description:test
    
    https://pagure.io/389-ds-base/issue/50151
    
    Author: William Brown <william@blackhats.net.au>
    
    Review by: spichugi, mreynolds, lkrispen (Thanks!)
    f19f2793
  • Mark Reynolds's avatar
    Ticket 50236 - memberOf should be more robust · ea24c43a
    Mark Reynolds authored
    Bug Description:  When doing a modrdn, or any memberOf update, if the entry
                      already has the memberOf attribute with the same value
                      the operation is incorrectly rejected.
    
    Fix Description:  If we get an error 20 (type or value exists) return success.
    
                      Also fixed a coding mistake that causes the wrong error
                      code to be returned.  This also required fixing the CI
                      test to check for the new correct errro code.
    
    https://pagure.io/389-ds-base/issue/50236
    
    Reviewed by:  firstyear, spichugi, and tbordaz (Thanks!!!)
    ea24c43a
  • Mark Reynolds's avatar
    Ticket 50238 - Failed modrdn can corrupt entry cache · a0639843
    Mark Reynolds authored
    Bug Description:  Under certain conditions (found under IPA) when a backend
                      transaction plugin fails and causes a modrdn operation to
                      fail the entry cache no longer contains the original/pre
                      entry, but instead it has the post modrdn'ed entry with
                      the original entry's ID
    
    Fix Description:  Upon failure, if the post entry is in the cache, then swap
                      it out with the original entry.
    
    https://pagure.io/389-ds-base/issue/50238
    
    Reviewed by: firstyear, spichugi, & tboardaz (Thanks!!!)
    a0639843
  • Mark Reynolds's avatar
    Ticket 50215 - UI - implement Database Tab in reachJS · 6e95c659
    Mark Reynolds authored
    Description:  Implement database tab in ReactJS.
    
    https://pagure.io/389-ds-base/issue/50215
    
    Reviewed by: spichugi & firstyear (Thanks!!)
    6e95c659
  • Ludwig Krispenz's avatar
    Ticket 50232 - export creates not importable ldif file · 0f785304
    Ludwig Krispenz authored
    Bug: If the RUV entry hasa  smaller entryid than the suffix entry it will be
    	exported before the suffix. If that ldif is used for import the RUV entry
    	is skipped and a new one generated with a different database generation
    
    Fix: Before exporting the RUV check that the suffix is alread exported, if not
    	make the RUV entry pending and write it after all othere entries
    
    Reviewed by: tbordaz, wbrown. Thanks
    0f785304
  • Ludwig Krispenz's avatar
    Ticket 50234 - one level search returns not matching entry · 0654777e
    Ludwig Krispenz authored
    Bug: if in a onelevel search the IDList for the parentid is smaller than the filter
    	threshold and smaller than the list generated by the search filter
    	then the intersection is aborted and all children are returned.
    
    Fix: In the above case we need to set the flag that the filter evaluation
    	cannot be bypassed
    
    Reviewed by: William, Thierry. Thanks
    0654777e
  • Mark Reynolds's avatar
    Ticket 50273 - reduce default replicaton agmt timeout · 951c499d
    Mark Reynolds authored
    Description:  The default timeout of 10 minutes is just too long.
                  Change default to 2 minutes.
    
    https://pagure.io/389-ds-base/issue/50273
    
    Reviewed by: tbordaz(Thanks!)
    
    (cherry picked from commit a703d101)
    951c499d
  • Simon Pichugin's avatar
    Issue 50041 - Add CLI functionality for special plugins · 1f15e966
    Simon Pichugin authored
    Description: Add the functionality for
    account-policy, attr-uniq, automember, dna, linked-attr,
    managed-entries, memberof, pass-through-auth, refer-init,
    retro-changelog, root-dn, usn commands.
    Make DSLdapObject create an entry with only DN and attributes
    (cases when RDN is not specified).
    Fix two small typos in pwpolicy CLI's arguments.
    Port test for DNA plugin.
    
    https://pagure.io/389-ds-base/issue/50041
    
    Reviewed by: wibrown, mreynolds, mhonek (Thanks!)
    
    (cherry picked from commit 46e28cb4)
    1f15e966
  • Mark Reynolds's avatar
    Ticket 50260 - backend txn plugins can corrupt entry cache · 09b5a2c3
    Mark Reynolds authored
    Bug Description:  If a nested backend txn plugin fails, any updates
                      it made that went into the entry cache still persist
                      after the database transaction is aborted.
    
    Fix Description:  In order to be sure the entry cache is not corrupted
                      after a backend txn plugin failure we need to flush
                      all the cache entries that were added to the cache
                      after the parent operation was started.
    
                      To do this we record the start time the original operation,
                      (or parent operation), and we record the time any entry
                      is added to the cache.  Then on failure we do a comparision
                      and remove the entry from the cache if it's not in use.
                      If it is in use we add a "invalid" flag which triggers
                      the entry to be removed when the cache entry is returned
                      by the owner.
    
    https://pagure.io/389-ds-base/issue/50260
    
    CI tested and ASAN approved.
    
    Reviewed by: firstyear, tbordaz, and lkrispen (Thanks!!!)
    
    (cherry picked from commit 7ba8a80c)
    09b5a2c3
  • Thierry Bordaz's avatar
    Ticket 49873: (cont) Contention on virtual attribute lookup · b998fed9
    Thierry Bordaz authored
    Bug Description:
    	The previous fix was incomplete.
    	It created the thread private counter before the fork.
    	The deamon process was not inheriting it.
    
    	There is a possiblity that an callback of an internal search
    	tries to update the map. (cos thread monitoring cos definition)
    	In such case the RW lock was first acquired in read at the top level
    	of the internal search, then later the callback try to acquire it in write.
    	this created a deadlock
    
    	It stored in in private counter a value (int) rather than the address of
    	of the value (int*).
    
    Fix Description:
    	The fix consists to create the thread private counter after the deamon creation.
    	In adding, when acquiring the lock in write, if the lock was already acquired
    	at the top level (in read), it release the lock and reset the counter. Then acquires
    	the lock in write.
    	In the opposite when releasing the lock in read, if the lock was not already acquired
    	it assumes it was acquired in write and do nothing
    
    https://pagure.io/389-ds-base/issue/49873
    
    Reviewed by: Mark Reynolds, William Brown (thanks !!)
    
    Platforms tested: F30
    
    Flag Day: no
    
    Doc impact: no
    b998fed9
  • Thierry Bordaz's avatar
    Ticket 50282 - OPERATIONS ERROR when trying to delete a group with automember members · ada0f84b
    Thierry Bordaz authored
    Bug Description:
    	When automember and memberof are enabled, if a user is member of a group
    	because of an automember rule. Then when the group is deleted,
    	memberof updates the member (to update 'memberof' attribute) that
    	trigger automember to reevaluate the automember rule and add the member
    	to the group. But at this time the group is already deleted.
    	Chaining back the failure up to the top level operation the deletion
    	of the group fails
    
    Fix Description:
    	The fix consists to check that if a automember rule tries to add a user
    	in a group, then to check that the group exists before updating it.
    
    https://pagure.io/389-ds-base/issue/50282
    
    Reviewed by: Mark Reynolds, William Brown
    
    Platforms tested: F29
    
    Flag Day: no
    
    Doc impact: no
    ada0f84b
  • Mark Reynolds's avatar
    Ticket 50077 - Do not automatically turn automember postop modifies on · 4ab9bd59
    Mark Reynolds authored
    Description:  Although we have set the new postop processing on by
                  default in the template-dse.ldif, we do not want to
                  enable it by default for upgrades (only new installs).
    
                  So if the attribute is not set, it is assumed "off".
    
    https://pagure.io/389-ds-base/issue/50077
    
    Reviewed by: firstyear(Thanks!)
    
    (cherry picked from commit d318d060)
    4ab9bd59
  • Thierry Bordaz's avatar
    Ticket 49561 - MEP plugin, upon direct op failure, will delete twice the same managed entry · 906e093f
    Thierry Bordaz authored
    Bug Description:
    	When a failure occurs during betxn_post plugin callback, the betxn_post plugins are called again.
    	This is to process some kind of undo action (for example usn or dna that manage counters).
    
    	If MEP plugin is called for a managing entry, it deletes the managed entry (that become a tombstone).
    	If later an other betxn_postop fails, then MEP is called again.
    	But as it does not detect the operation failure (for DEL and ADD), then it tries again
    	to delete the managed entry that is already a tombstone.
    
    Fix Description:
    	The MEP betxn_post plugin callbacks (ADD and DEL) should catch the operation failure
    	and return.
    	It is already in place for MODRDN and MOD.
    
    https://pagure.io/389-ds-base/issue/49561
    
    Reviewed by: Mark Reynold, thanks !!
    
    Platforms tested: F28
    
    Flag Day: no
    
    Doc impact: no
    906e093f
  • Mark Reynolds's avatar
    Ticket 50260 - Invalid cache flushing improvements · 67aaee47
    Mark Reynolds authored
    Description:  The original version of the fix only checked if backend
                  transaction "post" operation plugins failed, but it did
                  not check for errors from the backend transaction "pre"
                  operation plugin.  To address this we flush invalid
                  entries whenever any error occurs.
    
                  We were also not flushing invalid cache entries when
                  modrdn errors occurred.  Modrdns only make changes to
                  the DN hashtable inside the entry cache, but we were only
                  checking the ID hashtable.  So we also need to check the
                  DN hashtable in the entry cache for invalid entries.
    
    https://pagure.io/389-ds-base/issue/50260
    
    Reviewed by: firstyear & tbordaz(Thanks!!)
    
    (cherry picked from commit 33fbced2)
    67aaee47
  • Ludwig Krispenz's avatar
    Ticket 50265: the warning about skew time could last forever · c01d34cf
    Ludwig Krispenz authored
    Bug: if the local system time is set back more than 300 seconds
    	a worning about too much time skew is logged and the sampled
    	time is updated. This adjustment is done at every write operation
    	and can increase the time skew and be logged infinitely
    
    Fix: the intention of the adjustment was to avoid a roll over of seq_num
    	if the sampled time is not increased for more than 65k oberations.
    	But this is already handled with an explicite check for seq_num
    	rollover. The extra adjustment for negative time skew can be removed.
    
    Reviewed by: Thierry, William. Thanks.
    c01d34cf
  • Timo Aaltonen's avatar
  • Timo Aaltonen's avatar
  • Mark Reynolds's avatar
    Ticket 50300 - Fix memory leak in automember plugin · d55de4d5
    Mark Reynolds authored
    Description:  We were allocating a pblock long before it was used, and
                  we were returning from the function on an error before we
                  freed it.  The fix just allocates the pblock right before
                  it's used, and then it is properly freed.
    
    https://pagure.io/389-ds-base/issue/50300
    
    Reviewed by: mreynolds (one line commit rule)
    
    (cherry picked from commit 37f919a7)
    d55de4d5
  • Mark Reynolds's avatar
    Ticket 50289 - Fix various database UI issues · e568d474
    Mark Reynolds authored
    Description:
    
    Fixed these issues:
    
    - https://bugzilla.redhat.com/show_bug.cgi?id=1664621 - backup freezes when no suffix present
    
    - https://bugzilla.redhat.com/show_bug.cgi?id=1685395 - Perform Backup fails when Backend Name is not configured
    
    - https://bugzilla.redhat.com/show_bug.cgi?id=1688587 - typo when restarting instance
    
    - https://bugzilla.redhat.com/show_bug.cgi?id=1688775 - db tree breaks when suffix contains spaces.
    
    - https://bugzilla.redhat.com/show_bug.cgi?id=1688919 - backups fail with empty name
    
    Also fixed issue where if you start an instance in UI the configuration is correctly loaded.
    
    https://pagure.io/389-ds-base/issue/50289
    
    Reviewed by: spichugi(Thanks!)
    e568d474
  • Simon Pichugin's avatar
    Issue 50292 - Fix Plugin CLI and UI issues · 2b689f8b
    Simon Pichugin authored
    Description: Fix 'All plugins' tab rendering issue.
    Fix nsds5replicalastinitstatus typo.
    Fix generic_object_add logic for cases when RDN is in props and BaseDN is supplied.
    Add Posix Winsync API plugin
    Add PAM PTA plugin
    Fix underscore issues in plugin arguments.
    Fix Linked Attribute plugin Fixup task arguments and name.
    Change a 'print()' function to a 'log.info()' function.
    
    https://pagure.io/389-ds-base/issue/50292
    
    Reviewed by: mreynolds, wibrown (Thanks!)
    2b689f8b
  • Thierry Bordaz's avatar
    Ticket 49873 - (cont 2nd) Contention on virtual attribute lookup · 74490fb2
    Thierry Bordaz authored
    Bug Description:
    	SSL initialization does internal searches that access the vattr_global_lock
    	Thread private counter needs to be initialized by that time.
    	Currently it is initialized after SSL init.
    
    	Second problem was a leak of one 'int' per worker. It was used to keep the private counter.
    
    Fix Description:
    	Call of vattr_global_lock_create needs to be called before slapd_do_all_nss_ssl_init.
    	Also, 'main' may or may not fork, the initialization fo the thread private variable
    	is done either on the child or parent depending if main forks or not.
    
    	The leak is fixed using a destructor callback of the private variable and so
    	call PR_SetThreadPrivate only if there is no private variable.
    
    https://pagure.io/389-ds-base/issue/49873
    
    Reviewed by: Mark Reynolds, Simon Pichugi (thanks)
    
    Platforms tested: F28
    
    Flag Day: no
    
    Doc impact: no
    
    Ticket foo
    74490fb2
  • Thierry Bordaz's avatar
    f7d71790
  • Mark Reynolds's avatar
    Ticket 50308 - Fix memory leaks for repeat binds and replication · 85c3c304
    Mark Reynolds authored
    Description:  Fixed two memory leaks:
    
        - If a worker thread had multiple binds the "bind dn"
          thread data was leaked.
        - Memory leak when processing changes in the changelog
    
    https://pagure.io/389-ds-base/issue/50308
    
    Reviewed by: firstyear(Thanks!)
    
    (cherry picked from commit 6c2bb66f)
    85c3c304
  • Mark Reynolds's avatar
    Ticket 50308 - Revise memory leak fix · 11430afd
    Mark Reynolds authored
    Description;  Turns out the previous commit did not address
                  the changelog leak, and it introduced a compiler
                  warning.  This part of the fix is being reverted.
    
    https://pagure.io/389-ds-base/issue/50308
    (cherry picked from commit 1808f317)
    11430afd
  • Mark Reynolds's avatar
    Bump version to 1.4.0.22 · 9d84a40d
    Mark Reynolds authored
    9d84a40d
  • Timo Aaltonen's avatar
    Merge branch 'upstream' · b471f966
    Timo Aaltonen authored
    b471f966
  • Timo Aaltonen's avatar
    bump changelog · 9e4432a2
    Timo Aaltonen authored
    9e4432a2
  • Timo Aaltonen's avatar
    bc662300
......@@ -10,7 +10,7 @@ vendor="389 Project"
# PACKAGE_VERSION is constructed from these
VERSION_MAJOR=1
VERSION_MINOR=4
VERSION_MAINT=0.21
VERSION_MAINT=0.22
# NOTE: VERSION_PREREL is automatically set for builds made out of a git tree
VERSION_PREREL=
VERSION_DATE=$(date -u +%Y%m%d)
......
389-ds-base (1.4.0.22-1) unstable; urgency=medium
* New upstream bugfix release.
* control: Drop 389-ds-base from -legacy-tools Depends. (Closes:
#924265)
* fix-dsctl-remove.diff: Don't hardcode sysconfig. (Closes: #925221)
-- Timo Aaltonen <tjaalton@debian.org> Sat, 06 Apr 2019 00:32:06 +0300
389-ds-base (1.4.0.21-1) unstable; urgency=medium
* New upstream release.
......
......@@ -140,7 +140,6 @@ Description: 389 Directory Server suite - server
Package: 389-ds-base-legacy-tools
Architecture: any
Depends:
389-ds-base (= ${binary:Version}),
libmozilla-ldap-perl,
libnetaddr-ip-perl,
libperl4-corelibs-perl | perl (<< 5.12.3-7),
......
https://pagure.io/lib389/issue/107
--- a/src/lib389/lib389/instance/remove.py
+++ b/src/lib389/lib389/instance/remove.py
@@ -39,7 +39,7 @@ def remove_ds_instance(dirsrv, force=Fal
remove_paths['tmpfiles_d'] = dirsrv.ds_paths.tmpfiles_d + "/dirsrv-" + dirsrv.serverid + ".conf"
remove_paths['inst_dir'] = dirsrv.ds_paths.inst_dir
- marker_path = "%s/sysconfig/dirsrv-%s" % (dirsrv.ds_paths.sysconf_dir, dirsrv.serverid)
+ marker_path = "%s/dirsrv-%s" % (dirsrv.ds_paths.initconfig_dir, dirsrv.serverid)
etc_dirsrv_path = os.path.join(dirsrv.ds_paths.sysconf_dir, 'dirsrv/')
ssca_path = os.path.join(etc_dirsrv_path, 'ssca/')
......@@ -7,3 +7,4 @@ CVE-2017-15135.patch
perl-use-move-instead-of-rename.diff
icu_pkg-config.patch
fix-nss-path.diff
fix-dsctl-remove.diff
......@@ -4,7 +4,7 @@ import os
import ldap
from lib389.utils import ds_is_older
from lib389._constants import *
from lib389.plugins import AutoMembershipPlugin, AutoMembershipDefinition, AutoMembershipDefinitions
from lib389.plugins import AutoMembershipPlugin, AutoMembershipDefinition, AutoMembershipDefinitions, AutoMembershipRegexRule
from lib389._mapped_object import DSLdapObjects, DSLdapObject
from lib389 import agreement
from lib389.idm.user import UserAccount, UserAccounts, TEST_USER_PROPERTIES
......@@ -137,3 +137,115 @@ def test_adduser(automember_fixture, topo):
user = users.create(properties=TEST_USER_PROPERTIES)
assert group.is_member(user.dn)
user.delete()
def test_delete_default_group(automember_fixture, topo):
"""If memberof is enable and a user became member of default group
because of automember rule then delete the default group should succeeds
:id: 8b55d077-8851-45a2-a547-b28a7983a3c2
:setup: Standalone instance, enabled Auto Membership Plugin
:steps:
1. Enable memberof plugin
2. Create a user
3. Assert that the user is member of the default group
4. Delete the default group
:expectedresults:
1. Should be success
2. Should be success
3. Should be success
4. Should be success
"""
(group, automembers, automember) = automember_fixture
from lib389.plugins import MemberOfPlugin
memberof = MemberOfPlugin(topo.standalone)
memberof.enable()
topo.standalone.restart()
topo.standalone.setLogLevel(65536)
users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
user_1 = users.create_test_user(uid=1)
try:
assert group.is_member(user_1.dn)
group.delete()
error_lines = topo.standalone.ds_error_log.match('.*auto-membership-plugin - automember_update_member_value - group .default or target. does not exist .%s.$' % group.dn)
assert (len(error_lines) == 1)
finally:
user_1.delete()
topo.standalone.setLogLevel(0)
def test_delete_target_group(automember_fixture, topo):
"""If memberof is enabld and a user became member of target group
because of automember rule then delete the target group should succeeds
:id: bf5745e3-3de8-485d-8a68-e2fd460ce1cb
:setup: Standalone instance, enabled Auto Membership Plugin
:steps:
1. Recreate the default group if it was deleted before
2. Create a target group (using regex)
3. Create a target group automember rule (regex)
4. Enable memberof plugin
5. Create a user that goes into the target group
6. Assert that the user is member of the target group
7. Delete the target group
8. Check automember skipped the regex automember rule because target group did not exist
:expectedresults:
1. Should be success
2. Should be success
3. Should be success
4. Should be success
5. Should be success
6. Should be success
7. Should be success
8. Should be success
"""
(group, automembers, automember) = automember_fixture
# default group that may have been deleted in previous tests
try:
groups = Groups(topo.standalone, DEFAULT_SUFFIX)
group = groups.create(properties={'cn': 'testgroup'})
except:
pass
# target group that will receive regex automember
groups = Groups(topo.standalone, DEFAULT_SUFFIX)
group_regex = groups.create(properties={'cn': 'testgroup_regex'})
# regex automember definition
automember_regex_prop = {
'cn': 'automember regex',
'autoMemberTargetGroup': group_regex.dn,
'autoMemberInclusiveRegex': 'uid=.*1',
}
automember_regex_dn = 'cn=automember regex, %s' % automember.dn
automember_regexes = AutoMembershipRegexRule(topo.standalone, automember_regex_dn)
automember_regex = automember_regexes.create(properties=automember_regex_prop)
from lib389.plugins import MemberOfPlugin
memberof = MemberOfPlugin(topo.standalone)
memberof.enable()
topo.standalone.restart()
topo.standalone.setLogLevel(65536)
# create a user that goes into the target group but not in the default group
users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
user_1 = users.create_test_user(uid=1)
try:
assert group_regex.is_member(user_1.dn)
assert not group.is_member(user_1.dn)
# delete that target filter group
group_regex.delete()
error_lines = topo.standalone.ds_error_log.match('.*auto-membership-plugin - automember_update_member_value - group .default or target. does not exist .%s.$' % group_regex.dn)
# one line for default group and one for target group
assert (len(error_lines) == 1)
finally:
user_1.delete()
topo.standalone.setLogLevel(0)
......@@ -7,21 +7,23 @@
# --- END COPYRIGHT BLOCK ---
#
import pytest
import six
import ldap
from lib389.tasks import *
from lib389.utils import *
from lib389.topologies import topology_st
from lib389.plugins import SevenBitCheckPlugin, AttributeUniquenessPlugin, MemberOfPlugin
from lib389.plugins import (SevenBitCheckPlugin, AttributeUniquenessPlugin,
MemberOfPlugin, ManagedEntriesPlugin,
ReferentialIntegrityPlugin, MEPTemplates,
MEPConfigs)
from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES
from lib389.idm.group import Groups
from lib389._constants import DEFAULT_SUFFIX, PLUGIN_7_BIT_CHECK, PLUGIN_ATTR_UNIQUENESS, PLUGIN_MEMBER_OF
from lib389.idm.organizationalunit import OrganizationalUnits
from lib389.idm.group import Groups, Group
from lib389._constants import DEFAULT_SUFFIX
logging.getLogger(__name__).setLevel(logging.DEBUG)
log = logging.getLogger(__name__)
def test_betxt_7bit(topology_st):
"""Test that the 7-bit plugin correctly rejects an invalid update
......@@ -51,29 +53,24 @@ def test_betxt_7bit(topology_st):
sevenbc.enable()
topology_st.standalone.restart()
users = UserAccounts(topology_st.standalone, basedn=DEFAULT_SUFFIX)
user = users.create(properties=TEST_USER_PROPERTIES)
# Attempt a modrdn, this should fail
try:
with pytest.raises(ldap.LDAPError):
user.rename(BAD_RDN)
log.fatal('test_betxt_7bit: Modrdn operation incorrectly succeeded')
assert False
except ldap.LDAPError as e:
log.info('Modrdn failed as expected: error %s' % str(e))
# Make sure the operation did not succeed, attempt to search for the new RDN
with pytest.raises(ldap.LDAPError):
users.get(u'Fu\u00c4\u00e8')
# Make sure original entry is present
user_check = users.get("testuser")
assert user_check.dn.lower() == user.dn.lower()
assert user_check.dn == user.dn
#
# Cleanup - remove the user
#
user.delete()
log.info('test_betxt_7bit: PASSED')
......@@ -99,9 +96,6 @@ def test_betxn_attr_uniqueness(topology_st):
5. Test user entry should be removed
"""
USER1_DN = 'uid=test_entry1,' + DEFAULT_SUFFIX
USER2_DN = 'uid=test_entry2,' + DEFAULT_SUFFIX
attruniq = AttributeUniquenessPlugin(topology_st.standalone)
attruniq.enable()
topology_st.standalone.restart()
......@@ -116,8 +110,8 @@ def test_betxn_attr_uniqueness(topology_st):
'homeDirectory': '/home/testuser1'
})
try:
user2 = users.create(properties={
with pytest.raises(ldap.LDAPError):
users.create(properties={
'uid': ['testuser2', 'testuser1'],
'cn': 'testuser2',
'sn': 'user2',
......@@ -125,10 +119,6 @@ def test_betxn_attr_uniqueness(topology_st):
'gidNumber': '2002',
'homeDirectory': '/home/testuser2'
})
log.fatal('test_betxn_attr_uniqueness: The second entry was incorrectly added.')
assert False
except ldap.LDAPError as e:
log.error('test_betxn_attr_uniqueness: Failed to add test user as expected:')
user1.delete()
......@@ -156,24 +146,14 @@ def test_betxn_memberof(topology_st):
5. Add operation should FAIL
"""
ENTRY1_DN = 'cn=group1,' + DEFAULT_SUFFIX
ENTRY2_DN = 'cn=group2,' + DEFAULT_SUFFIX
PLUGIN_DN = 'cn=' + PLUGIN_MEMBER_OF + ',cn=plugins,cn=config'
memberof = MemberOfPlugin(topology_st.standalone)
memberof.enable()
memberof.set_autoaddoc('referral')
# memberof.add_groupattr('member') # This is already the default.
topology_st.standalone.restart()
groups = Groups(topology_st.standalone, DEFAULT_SUFFIX)
group1 = groups.create(properties={
'cn' : 'group1',
})
group2 = groups.create(properties={
'cn' : 'group2',
})
group1 = groups.create(properties={'cn': 'group1'})
group2 = groups.create(properties={'cn': 'group2'})
# We may need to mod groups to not have nsMemberOf ... ?
if not ds_is_older('1.3.7'):
......@@ -181,20 +161,180 @@ def test_betxn_memberof(topology_st):
group2.remove('objectClass', 'nsMemberOf')
# Add group2 to group1 - it should fail with objectclass violation
try:
with pytest.raises(ldap.OBJECT_CLASS_VIOLATION):
group1.add_member(group2.dn)
topology_st.standalone.modify_s(ENTRY1_DN, [(ldap.MOD_ADD, 'member', ENTRY2_DN)])
log.fatal('test_betxn_memberof: Group2 was incorrectly allowed to be added to group1')
assert False
except ldap.LDAPError as e:
log.info('test_betxn_memberof: Group2 was correctly rejected (mod add): error')
#
# verify entry cache reflects the current/correct state of group1
assert not group1.is_member(group2.dn)
# Done
#
log.info('test_betxn_memberof: PASSED')
def test_betxn_modrdn_memberof_cache_corruption(topology_st):
"""Test modrdn operations and memberOf be txn post op failures
:id: 70d0b96e-b693-4bf7-bbf5-102a66ac5994
:setup: Standalone instance
:steps: 1. Enable and configure memberOf plugin
2. Set memberofgroupattr="member" and memberofAutoAddOC="nsContainer"
3. Create group and user outside of memberOf plugin scope
4. Do modrdn to move group into scope
5. Do modrdn to move group into scope (again)
:expectedresults:
1. memberOf plugin plugin should be ON
2. Set memberofgroupattr="member" and memberofAutoAddOC="nsContainer" should PASS
3. Creating group and user should PASS
4. Modrdn should fail with objectclass violation
5. Second modrdn should also fail with objectclass violation
"""
peoplebase = 'ou=people,%s' % DEFAULT_SUFFIX
memberof = MemberOfPlugin(topology_st.standalone)
memberof.enable()
memberof.set_autoaddoc('nsContainer') # Bad OC
memberof.set('memberOfEntryScope', peoplebase)
memberof.set('memberOfAllBackends', 'on')
topology_st.standalone.restart()
groups = Groups(topology_st.standalone, DEFAULT_SUFFIX)
group = groups.create(properties={
'cn': 'group',
})
# Create user and add it to group
users = UserAccounts(topology_st.standalone, basedn=DEFAULT_SUFFIX)
user = users.ensure_state(properties=TEST_USER_PROPERTIES)
if not ds_is_older('1.3.7'):
user.remove('objectClass', 'nsMemberOf')
group.add_member(user.dn)
# Attempt modrdn that should fail, but the original entry should stay in the cache
with pytest.raises(ldap.OBJECT_CLASS_VIOLATION):
group.rename('cn=group_to_people', newsuperior=peoplebase)
# Should fail, but not with NO_SUCH_OBJECT as the original entry should still be in the cache
with pytest.raises(ldap.OBJECT_CLASS_VIOLATION):
group.rename('cn=group_to_people', newsuperior=peoplebase)
# Done
log.info('test_betxn_modrdn_memberof: PASSED')
def test_ri_and_mep_cache_corruption(topology_st):
"""Test RI plugin aborts change after MEP plugin fails.
This is really testing the entry cache for corruption
:id: 70d0b96e-b693-4bf7-bbf5-102a66ac5995
:setup: Standalone instance
:steps: 1. Enable and configure mep and ri plugins
2. Add user and add it to a group
3. Disable MEP plugin and remove MEP group
4. Delete user
5. Check that user is still a member of the group
:expectedresults:
1. Success
2. Success
3. Success
4. It fails with NO_SUCH_OBJECT
5. Success
"""
# Start plugins
topology_st.standalone.config.set('nsslapd-dynamic-plugins', 'on')
mep_plugin = ManagedEntriesPlugin(topology_st.standalone)
mep_plugin.enable()
ri_plugin = ReferentialIntegrityPlugin(topology_st.standalone)
ri_plugin.enable()
# Add our org units
ous = OrganizationalUnits(topology_st.standalone, DEFAULT_SUFFIX)
ou_people = ous.create(properties={'ou': 'managed_people'})
ou_groups = ous.create(properties={'ou': 'managed_groups'})
# Configure MEP
mep_templates = MEPTemplates(topology_st.standalone, DEFAULT_SUFFIX)
mep_template1 = mep_templates.create(properties={
'cn': 'MEP template',
'mepRDNAttr': 'cn',
'mepStaticAttr': 'objectclass: posixGroup|objectclass: extensibleObject'.split('|'),
'mepMappedAttr': 'cn: $cn|uid: $cn|gidNumber: $uidNumber'.split('|')
})
mep_configs = MEPConfigs(topology_st.standalone)
mep_configs.create(properties={'cn': 'config',
'originScope': ou_people.dn,
'originFilter': 'objectclass=posixAccount',
'managedBase': ou_groups.dn,
'managedTemplate': mep_template1.dn})
# Add an entry that meets the MEP scope
users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX,
rdn='ou={}'.format(ou_people.rdn))
user = users.create(properties={
'uid': 'test-user1',
'cn': 'test-user',
'sn': 'test-user',
'uidNumber': '10011',
'gidNumber': '20011',
'homeDirectory': '/home/test-user1'
})
# Add group
groups = Groups(topology_st.standalone, DEFAULT_SUFFIX)
user_group = groups.ensure_state(properties={'cn': 'group', 'member': user.dn})
# Check if a managed group entry was created
mep_group = Group(topology_st.standalone, dn='cn={},{}'.format(user.rdn, ou_groups.dn))
if not mep_group.exists():
log.fatal("MEP group was not created for the user")
assert False
# Test MEP be txn pre op failure does not corrupt entry cache
# Should get the same exception for both rename attempts
with pytest.raises(ldap.UNWILLING_TO_PERFORM):
mep_group.rename("cn=modrdn group")
with pytest.raises(ldap.UNWILLING_TO_PERFORM):
mep_group.rename("cn=modrdn group")
# Mess with MEP so it fails
mep_plugin.disable()
mep_group.delete()
mep_plugin.enable()
# Add another group to verify entry cache is not corrupted
test_group = groups.create(properties={'cn': 'test_group'})
# Delete user, should fail in MEP be txn post op, and user should still be a member
with pytest.raises(ldap.NO_SUCH_OBJECT):
user.delete()
# Verify membership is intact
if not user_group.is_member(user.dn):
log.fatal("Member was incorrectly removed from the group!! Or so it seems")
# Restart server and test again in case this was a cache issue
topology_st.standalone.restart()
if user_group.is_member(user.dn):
log.info("The entry cache was corrupted")
assert False
assert False
# Verify test group is still found in entry cache by deleting it
test_group.delete()
# Success
log.info("Test PASSED")
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
......
......@@ -11,13 +11,12 @@ import pytest
import os
import time
import ldap
import subprocess
from random import sample
from lib389.utils import ds_is_older, ensure_list_bytes, ensure_bytes, ensure_str
from lib389.topologies import topology_m1h1c1 as topo, topology_st, topology_m2 as topo_m2
from lib389._constants import *
from lib389.plugins import MemberOfPlugin
from lib389 import agreement, Entry
from lib389 import Entry
from lib389.idm.user import UserAccount, UserAccounts, TEST_USER_PROPERTIES
from lib389.idm.group import Groups, Group
from lib389.replica import ReplicationManager
......@@ -49,7 +48,7 @@ def add_users(topo_m2, users_num, suffix):
users_list = []
users = UserAccounts(topo_m2.ms["master1"], suffix, rdn=None)
log.info('Adding %d users' % users_num)
for num in sample(range(1000), users_num):
for num in sample(list(range(1000)), users_num):
num_ran = int(round(num))
USER_NAME = 'test%05d' % num_ran
user = users.create(properties={
......@@ -427,7 +426,7 @@ def rename_entry(server, cn, from_subtree, to_subtree):
server.rename_s(dn, nrdn, newsuperior=to_subtree, delold=0)
def _find_memberof(server, user_dn=None, group_dn=None, find_result=True):
def _find_memberof_ext(server, user_dn=None, group_dn=None, find_result=True):
assert (server)
assert (user_dn)
assert (group_dn)
......@@ -495,18 +494,19 @@ def test_memberof_group(topology_st):
dn2 = '%s,%s' % ('uid=test_m2', SUBTREE_1)
g1 = '%s,%s' % ('cn=g1', SUBTREE_1)
g2 = '%s,%s' % ('cn=g2', SUBTREE_2)
_find_memberof(inst, dn1, g1, True)
_find_memberof(inst, dn2, g1, True)
_find_memberof(inst, dn1, g2, False)
_find_memberof(inst, dn2, g2, False)
_find_memberof_ext(inst, dn1, g1, True)
_find_memberof_ext(inst, dn2, g1, True)
_find_memberof_ext(inst, dn1, g2, False)
_find_memberof_ext(inst, dn2, g2, False)
rename_entry(inst, 'cn=g2', SUBTREE_2, SUBTREE_1)
g2n = '%s,%s' % ('cn=g2-new', SUBTREE_1)
_find_memberof(inst, dn1, g1, True)
_find_memberof(inst, dn2, g1, True)
_find_memberof(inst, dn1, g2n, True)
_find_memberof(inst, dn2, g2n, True)
_find_memberof_ext(inst, dn1, g1, True)
_find_memberof_ext(inst, dn2, g1, True)
_find_memberof_ext(inst, dn1, g2n, True)
_find_memberof_ext(inst, dn2, g2n, True)
def _config_memberof_entrycache_on_modrdn_failure(server):
......@@ -517,11 +517,13 @@ def _config_memberof_entrycache_on_modrdn_failure(server):
(ldap.MOD_REPLACE, 'memberOfEntryScope', peoplebase.encode()),
(ldap.MOD_REPLACE, 'memberOfAutoAddOC', b'nsMemberOf')])
def _disable_auto_oc_memberof(server):
MEMBEROF_PLUGIN_DN = ('cn=' + PLUGIN_MEMBER_OF + ',cn=plugins,cn=config')
server.modify_s(MEMBEROF_PLUGIN_DN,
[(ldap.MOD_REPLACE, 'memberOfAutoAddOC', b'nsContainer')])
@pytest.mark.ds49967
def test_entrycache_on_modrdn_failure(topology_st):
"""This test checks that when a modrdn fails, the destination entry is not returned by a search
......@@ -657,7 +659,7 @@ def test_entrycache_on_modrdn_failure(topology_st):
topology_st.standalone.rename_s(group2_dn, 'cn=group_in2', newsuperior=peoplebase, delold=0)
topology_st.standalone.log.info("This is unexpected, modrdn should fail as the member entry have not the appropriate objectclass")
assert False
except ldap.OPERATIONS_ERROR:
except ldap.OBJECT_CLASS_VIOLATION:
pass
# retrieve the entry having the specific description value
......@@ -671,9 +673,11 @@ def test_entrycache_on_modrdn_failure(topology_st):
assert ent.dn == group2_dn
assert found
def _config_memberof_silent_memberof_failure(server):
_config_memberof_entrycache_on_modrdn_failure(server)
def test_silent_memberof_failure(topology_st):
"""This test checks that if during a MODRDN, the memberof plugin fails
then MODRDN also fails
......@@ -817,7 +821,7 @@ def test_silent_memberof_failure(topology_st):
topology_st.standalone.rename_s(group2_dn, 'cn=group_in2', newsuperior=peoplebase, delold=0)
topology_st.standalone.log.info("This is unexpected, modrdn should fail as the member entry have not the appropriate objectclass")
assert False
except ldap.OPERATIONS_ERROR:
except ldap.OBJECT_CLASS_VIOLATION:
pass
# Check the those entries have not memberof
......@@ -843,7 +847,7 @@ def test_silent_memberof_failure(topology_st):
except ldap.OPERATIONS_ERROR:
pass
# Check the those entries have not memberof
# Check the those entries do not have memberof
for i in (4, 5):
user_dn = 'cn=user%d,%s' % (i, peoplebase)
ent = topology_st.standalone.getEntry(user_dn, ldap.SCOPE_BASE, "(objectclass=*)", ['memberof'])
......
......@@ -7,10 +7,11 @@
# --- END COPYRIGHT BLOCK ---
#
import pytest
import time
from lib389.tasks import *
from lib389.utils import *
from lib389.topologies import topology_st
from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES
from lib389._constants import DN_DM, DEFAULT_SUFFIX, PASSWORD
logging.getLogger(__name__).setLevel(logging.DEBUG)
......@@ -35,6 +36,10 @@ def test_basic(topology_st):
6. Attempt to change the password to previous passwords
7. Reset password by Directory Manager (admin reset)
8. Try and change the password to the previous password before the reset
9. Test passwordInHistory set to "0" rejects only the current password
10. Test passwordInHistory set to "2" rejects previous passwords
:expectedresults:
1. Password history policy should be configured successfully
2. User should be added successfully
......@@ -47,10 +52,10 @@ def test_basic(topology_st):
7. Password should be successfully reset
8. Password change should be correctly rejected
with Constrant Violation error
9. Success
10. Success
"""
USER_DN = 'uid=testuser,' + DEFAULT_SUFFIX
#
# Configure password history policy and add a test user
#
......@@ -58,37 +63,25 @@ def test_basic(topology_st):
topology_st.standalone.config.replace_many(('passwordHistory', 'on'),
('passwordInHistory', '3'),
('passwordChange', 'on'),
('passwordStorageScheme', 'CLEAR'))
('passwordStorageScheme', 'CLEAR'),
('nsslapd-auditlog-logging-enabled', 'on'))
log.info('Configured password policy.')
except ldap.LDAPError as e:
log.fatal('Failed to configure password policy: ' + str(e))
assert False
time.sleep(1)
try:
topology_st.standalone.add_s(Entry((USER_DN, {
'objectclass': ['top', 'extensibleObject'],
'sn': 'user',
'cn': 'test user',
'uid': 'testuser',
'userpassword': 'password'})))
except ldap.LDAPError as e:
log.fatal('Failed to add test user' + USER_DN + ': error ' + str(e))
assert False
users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX)
user = users.create(properties=TEST_USER_PROPERTIES)
user.set('userpassword', 'password')
user.rebind('password')
#
# Test that password history is enforced.
#
try:
topology_st.standalone.simple_bind_s(USER_DN, 'password')
except ldap.LDAPError as e:
log.fatal('Failed to bind as user: ' + str(e))
assert False
# Attempt to change password to the same password
try:
topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
'userpassword', b'password')])
user.set('userpassword', 'password')
log.info('Incorrectly able to to set password to existing password.')
assert False
except ldap.CONSTRAINT_VIOLATION:
......@@ -100,110 +93,109 @@ def test_basic(topology_st):
#
# Keep changing password until we fill the password history (3)
#
user.set('userpassword', 'password1')
user.rebind('password1')
user.set('userpassword', 'password2')
user.rebind('password2')
user.set('userpassword', 'password3')
user.rebind('password3')
user.set('userpassword', 'password4')
user.rebind('password4')
time.sleep(1)
# password1
try:
topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
'userpassword', b'password1')])
except ldap.LDAPError as e:
log.fatal('Failed to change password: ' + str(e))
assert False
try:
topology_st.standalone.simple_bind_s(USER_DN, 'password1')
except ldap.LDAPError as e:
log.fatal('Failed to bind as user using "password1": ' + str(e))
#
# Check that we only have 3 passwords stored in history
#
pwds = user.get_attr_vals('passwordHistory')
if len(pwds) != 3:
log.fatal('Incorrect number of passwords stored in history: %d' %
len(pwds))
log.error('password history: ' + str(pwds))
assert False
time.sleep(1)
else:
log.info('Correct number of passwords found in history.')
# password2
#
# Attempt to change the password to previous passwords
#
try:
topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
'userpassword', b'password2')])
except ldap.LDAPError as e:
log.fatal('Failed to change password: ' + str(e))
user.set('userpassword', 'password1')
log.fatal('Incorrectly able to to set password to previous password1.')
log.error('password history: ' + str(user.get_attr_vals('passwordhistory')))
assert False
try:
topology_st.standalone.simple_bind_s(USER_DN, 'password2')
except ldap.CONSTRAINT_VIOLATION:
log.info('Password change correctly rejected')
except ldap.LDAPError as e:
log.fatal('Failed to bind as user using "password2": ' + str(e))
log.fatal('Failed to attempt to change password: ' + str(e))
assert False
time.sleep(1)
# password3
try:
topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
'userpassword', b'password3')])
except ldap.LDAPError as e:
log.fatal('Failed to change password: ' + str(e))
user.set('userpassword', 'password2')
log.fatal('Incorrectly able to to set password to previous password2.')
log.error('password history: ' + str(user.get_attr_vals('passwordhistory')))
assert False
try:
topology_st.standalone.simple_bind_s(USER_DN, 'password3')
except ldap.CONSTRAINT_VIOLATION:
log.info('Password change correctly rejected')
except ldap.LDAPError as e:
log.fatal('Failed to bind as user using "password3": ' + str(e))
log.fatal('Failed to attempt to change password: ' + str(e))
assert False
time.sleep(1)
# password4
try:
topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
'userpassword', b'password4')])
except ldap.LDAPError as e:
log.fatal('Failed to change password: ' + str(e))
user.set('userpassword', 'password3')
log.fatal('Incorrectly able to to set password to previous password3.')
log.error('password history: ' + str(user.get_attr_vals('passwordhistory')))
assert False
try:
topology_st.standalone.simple_bind_s(USER_DN, 'password4')
except ldap.CONSTRAINT_VIOLATION:
log.info('Password change correctly rejected')
except ldap.LDAPError as e:
log.fatal('Failed to bind as user using "password4": ' + str(e))
log.fatal('Failed to attempt to change password: ' + str(e))
assert False
time.sleep(1)
#
# Check that we only have 3 passwords stored in history
# Reset password by Directory Manager(admin reset)
#
try:
entry = topology_st.standalone.search_s(USER_DN, ldap.SCOPE_BASE,
'objectclass=*',
['passwordHistory'])
pwds = entry[0].getValues('passwordHistory')
if len(pwds) != 3:
log.fatal('Incorrect number of passwords stored in histry: %d' %
len(pwds))
assert False
else:
log.info('Correct number of passwords found in history.')
topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
except ldap.LDAPError as e:
log.fatal('Failed to get user entry: ' + str(e))
log.fatal('Failed to bind as rootDN: ' + str(e))
assert False
user.set('userpassword', 'password-reset')
time.sleep(1)
#
# Attempt to change the password to previous passwords
#
# Try and change the password to the previous password before the reset
try:
topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
'userpassword', b'password1')])
log.info('Incorrectly able to to set password to previous password1.')
user.rebind('password-reset')
user.set('userpassword', 'password4')
log.fatal('Incorrectly able to to set password to previous password4.')
log.error('password history: ' + str(user.get_attr_vals('passwordhistory')))
assert False
except ldap.CONSTRAINT_VIOLATION:
log.info('Password change correctly rejected')
except ldap.LDAPError as e:
log.fatal('Failed to attempt to change password: ' + str(e))
assert False
time.sleep(1)
#
# Test passwordInHistory to 0
#
try:
topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
'userpassword', b'password2')])
log.info('Incorrectly able to to set password to previous password2.')
topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
except ldap.LDAPError as e:
log.fatal('Failed to bind as rootDN: ' + str(e))
assert False
except ldap.CONSTRAINT_VIOLATION:
log.info('Password change correctly rejected')
try:
topology_st.standalone.config.replace('passwordInHistory', '0')
log.info('Configured passwordInHistory to 0.')
except ldap.LDAPError as e:
log.fatal('Failed to attempt to change password: ' + str(e))
log.fatal('Failed to configure password policy (passwordInHistory to 0): ' + str(e))
assert False
# Verify the older passwords in the entry (passwordhistory) are ignored
user.rebind('password-reset')
user.set('userpassword', 'password4')
try:
topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
'userpassword', b'password3')])
log.info('Incorrectly able to to set password to previous password3.')
user.set('userpassword', 'password4')
log.fatal('Incorrectly able to to set password to current password4.')
log.error('password history: ' + str(user.get_attr_vals('passwordhistory')))
assert False
except ldap.CONSTRAINT_VIOLATION:
log.info('Password change correctly rejected')
......@@ -211,8 +203,12 @@ def test_basic(topology_st):
log.fatal('Failed to attempt to change password: ' + str(e))
assert False
# Need to make one successful update so history list is reset
user.set('userpassword', 'password5')
#
# Reset password by Directory Manager(admin reset)
# Set the history count back to a positive value and make sure things still work
# as expected
#
try:
topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
......@@ -221,33 +217,34 @@ def test_basic(topology_st):
assert False
try:
topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
'userpassword',
b'password-reset')])
topology_st.standalone.config.replace('passwordInHistory', '2')
log.info('Configured passwordInHistory to 2.')
except ldap.LDAPError as e:
log.fatal('Failed to attempt to reset password: ' + str(e))
log.fatal('Failed to configure password policy (passwordInHistory to 2): ' + str(e))
assert False
time.sleep(1)
# Try and change the password to the previous password before the reset
try:
topology_st.standalone.simple_bind_s(USER_DN, 'password-reset')
user.rebind('password5')
user.set('userpassword', 'password5')
log.fatal('Incorrectly able to to set password to current password5.')
log.error('password history: ' + str(user.get_attr_vals('passwordhistory')))
assert False
except ldap.CONSTRAINT_VIOLATION:
log.info('Password change correctly rejected')
except ldap.LDAPError as e:
log.fatal('Failed to bind as user: ' + str(e))
log.fatal('Failed to attempt to change password: ' + str(e))
assert False
time.sleep(1)
# Test that old password that was in history is not being checked
try:
topology_st.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
'userpassword', b'password4')])
log.info('Incorrectly able to to set password to previous password4.')
assert False
except ldap.CONSTRAINT_VIOLATION:
log.info('Password change correctly rejected')
user.set('userpassword', 'password1')
except ldap.LDAPError as e:
log.fatal('Failed to attempt to change password: ' + str(e))
log.error('password history: ' + str(user.get_attr_vals('passwordhistory')))
assert False
# Done
log.info('Test suite PASSED.')
......
......@@ -18,7 +18,7 @@ from lib389.utils import *
from lib389.plugins import *
from lib389._constants import *
from lib389.dseldif import DSEldif
from lib389.idm.user import UserAccounts, UserAccount
from lib389.idm.user import UserAccounts
from lib389.idm.group import Groups
from lib389.idm.organizationalunit import OrganizationalUnits
from lib389.idm.domain import Domain
......
# --- BEGIN COPYRIGHT BLOCK ---
# Copyright (C) 2019 Red Hat, Inc.
# All rights reserved.
#
# License: GPL (version 3 or any later version).
# See LICENSE for details.
# --- END COPYRIGHT BLOCK ---
#
"""Test DNA plugin functionality"""
import logging
import pytest
from lib389._constants import DEFAULT_SUFFIX
from lib389.plugins import DNAPlugin, DNAPluginSharedConfigs, DNAPluginConfigs
from lib389.idm.organizationalunit import OrganizationalUnits
from lib389.idm.user import UserAccounts
from lib389.topologies import topology_st
import ldap
log = logging.getLogger(__name__)
@pytest.mark.ds47937
def test_dnatype_only_valid(topology_st):
"""Test that DNA plugin only accepts valid attributes for "dnaType"
:id: 0878ecff-5fdc-47d7-8c8f-edf4556f9746
:setup: Standalone Instance
:steps:
1. Create a use entry
2. Create DNA shared config entry container
3. Create DNA shared config entry
4. Add DNA plugin config entry
5. Enable DNA plugin
6. Restart the instance
7. Replace dnaType with invalid value
:expectedresults:
1. Successful
2. Successful
3. Successful
4. Successful
5. Successful
6. Successful
7. Unwilling to perform exception should be raised
"""
inst = topology_st.standalone
plugin = DNAPlugin(inst)
log.info("Creating an entry...")
users = UserAccounts(inst, DEFAULT_SUFFIX)
users.create_test_user(uid=1)
log.info("Creating \"ou=ranges\"...")
ous = OrganizationalUnits(inst, DEFAULT_SUFFIX)
ou_ranges = ous.create(properties={'ou': 'ranges'})
ou_people = ous.get("People")
log.info("Creating DNA shared config entry...")
shared_configs = DNAPluginSharedConfigs(inst, ou_ranges.dn)
shared_configs.create(properties={'dnaHostName': str(inst.host),
'dnaPortNum': str(inst.port),
'dnaRemainingValues': '9501'})
log.info("Add dna plugin config entry...")
configs = DNAPluginConfigs(inst, plugin.dn)
config = configs.create(properties={'cn': 'dna config',
'dnaType': 'description',
'dnaMaxValue': '10000',
'dnaMagicRegen': '0',
'dnaFilter': '(objectclass=top)',
'dnaScope': ou_people.dn,
'dnaNextValue': '500',
'dnaSharedCfgDN': ou_ranges.dn})
log.info("Enable the DNA plugin...")
plugin.enable()
log.info("Restarting the server...")
inst.restart()
log.info("Apply an invalid attribute to the DNA config(dnaType: foo)...")
with pytest.raises(ldap.UNWILLING_TO_PERFORM):
config.replace('dnaType', 'foo')
# --- BEGIN COPYRIGHT BLOCK ---
# Copyright (C) 2016 Red Hat, Inc.
# All rights reserved.
#
# License: GPL (version 3 or any later version).
# See LICENSE for details.
# --- END COPYRIGHT BLOCK ---
#
import logging
import time
import ldap
import pytest
from lib389 import Entry
from lib389._constants import *
from lib389.topologies import topology_st
log = logging.getLogger(__name__)
def test_ticket47937(topology_st):
"""
Test that DNA plugin only accepts valid attributes for "dnaType"
"""
log.info("Creating \"ou=people\"...")
try:
topology_st.standalone.add_s(Entry(('ou=people,' + SUFFIX, {
'objectclass': 'top organizationalunit'.split(),
'ou': 'people'
})))
except ldap.ALREADY_EXISTS:
pass
except ldap.LDAPError as e:
log.error('Failed to add ou=people org unit: error ' + e.args[0]['desc'])
assert False
log.info("Creating \"ou=ranges\"...")
try:
topology_st.standalone.add_s(Entry(('ou=ranges,' + SUFFIX, {
'objectclass': 'top organizationalunit'.split(),
'ou': 'ranges'
})))
except ldap.LDAPError as e:
log.error('Failed to add ou=ranges org unit: error ' + e.args[0]['desc'])
assert False
log.info("Creating \"cn=entry\"...")
try:
topology_st.standalone.add_s(Entry(('cn=entry,ou=people,' + SUFFIX, {
'objectclass': 'top groupofuniquenames'.split(),
'cn': 'entry'
})))
except ldap.LDAPError as e:
log.error('Failed to add test entry: error ' + e.args[0]['desc'])
assert False
log.info("Creating DNA shared config entry...")
try:
topology_st.standalone.add_s(Entry(('dnaHostname=localhost.localdomain+dnaPortNum=389,ou=ranges,%s' % SUFFIX, {
'objectclass': 'top dnaSharedConfig'.split(),
'dnaHostname': 'localhost.localdomain',
'dnaPortNum': '389',
'dnaSecurePortNum': '636',
'dnaRemainingValues': '9501'
})))
except ldap.LDAPError as e:
log.error('Failed to add shared config entry: error ' + e.args[0]['desc'])
assert False
log.info("Add dna plugin config entry...")
try:
topology_st.standalone.add_s(
Entry(('cn=dna config,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config', {
'objectclass': 'top dnaPluginConfig'.split(),
'dnaType': 'description',
'dnaMaxValue': '10000',
'dnaMagicRegen': '0',
'dnaFilter': '(objectclass=top)',
'dnaScope': 'ou=people,%s' % SUFFIX,
'dnaNextValue': '500',
'dnaSharedCfgDN': 'ou=ranges,%s' % SUFFIX
})))
except ldap.LDAPError as e:
log.error('Failed to add DNA config entry: error ' + e.args[0]['desc'])
assert False
log.info("Enable the DNA plugin...")
try:
topology_st.standalone.plugins.enable(name=PLUGIN_DNA)
except e:
log.error("Failed to enable DNA Plugin: error " + e.args[0]['desc'])
assert False
log.info("Restarting the server...")
topology_st.standalone.stop(timeout=120)
time.sleep(1)
topology_st.standalone.start(timeout=120)
time.sleep(3)
log.info("Apply an invalid attribute to the DNA config(dnaType: foo)...")
try:
topology_st.standalone.modify_s('cn=dna config,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config',
[(ldap.MOD_REPLACE, 'dnaType', b'foo')])
except ldap.LDAPError as e:
log.info('Operation failed as expected (error: %s)' % e.args[0]['desc'])
else:
log.error('Operation incorectly succeeded! Test Failed!')
assert False
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
CURRENT_FILE = os.path.realpath(__file__)
pytest.main("-s %s" % CURRENT_FILE)
This diff is collapsed.
# --- BEGIN COPYRIGHT BLOCK ---
# Copyright (C) 2016 Red Hat, Inc.
# All rights reserved.
#
# License: GPL (version 3 or any later version).
# See LICENSE for details.
# --- END COPYRIGHT BLOCK ---
#
import logging
import pytest
# from lib389.tasks import *
# from lib389.utils import *
from lib389.topologies import topology_st
from lib389.replica import ReplicationManager,Replicas
from lib389._constants import DEFAULT_SUFFIX, BACKEND_NAME
from lib389.idm.user import UserAccounts
from lib389.idm.organization import Organization
from lib389.idm.organizationalunit import OrganizationalUnit
log = logging.getLogger(__name__)
NORMAL_SUFFIX = 'o=normal'
NORMAL_BACKEND_NAME = 'normal'
REVERSE_SUFFIX = 'o=reverse'
REVERSE_BACKEND_NAME = 'reverse'
def _enable_replica(instance, suffix):
repl = ReplicationManager(DEFAULT_SUFFIX)
repl._ensure_changelog(instance)
replicas = Replicas(instance)
replicas.create(properties={
'cn': 'replica',
'nsDS5ReplicaRoot': suffix,
'nsDS5ReplicaId': '1',
'nsDS5Flags': '1',
'nsDS5ReplicaType': '3'
})
def _populate_suffix(instance, suffixname):
o = Organization(instance, 'o={}'.format(suffixname))
o.create(properties={
'o': suffixname,
'description': 'test'
})
ou = OrganizationalUnit(instance, 'ou=people,o={}'.format(suffixname))
ou.create(properties={
'ou': 'people'
})
def _get_replica_generation(instance, suffix):
replicas = Replicas(instance)
replica = replicas.get(suffix)
ruv = replica.get_ruv()
return ruv._data_generation
def _test_export_import(instance, suffix, backend):
before_generation = _get_replica_generation(instance, suffix)
instance.stop()
instance.db2ldif(
bename=backend,
suffixes=[suffix],
excludeSuffixes=[],
encrypt=False,
repl_data=True,
outputfile="/tmp/output_file",
)
instance.ldif2db(
bename=None,
excludeSuffixes=None,
encrypt=False,
suffixes=[suffix],
import_file="/tmp/output_file",
)
instance.start()
after_generation = _get_replica_generation(instance, suffix)
assert (before_generation == after_generation)
def test_ticket50232_normal(topology_st):
"""
The fix for ticket 50232
The test sequence is:
- create suffix
- add suffix entry and some child entries
- "normally" done after populating suffix: enable replication
- get RUV and database generation
- export -r
- import
- get RUV and database generation
- assert database generation has not changed
"""
log.info('Testing Ticket 50232 - export creates not imprtable ldif file, normal creation order')
topology_st.standalone.backend.create(NORMAL_SUFFIX, {BACKEND_NAME: NORMAL_BACKEND_NAME})
topology_st.standalone.mappingtree.create(NORMAL_SUFFIX, bename=NORMAL_BACKEND_NAME, parent=None)
_populate_suffix(topology_st.standalone, NORMAL_BACKEND_NAME)
repl = ReplicationManager(DEFAULT_SUFFIX)
repl._ensure_changelog(topology_st.standalone)
replicas = Replicas(topology_st.standalone)
replicas.create(properties={
'cn': 'replica',
'nsDS5ReplicaRoot': NORMAL_SUFFIX,
'nsDS5ReplicaId': '1',
'nsDS5Flags': '1',
'nsDS5ReplicaType': '3'
})
_test_export_import(topology_st.standalone, NORMAL_SUFFIX, NORMAL_BACKEND_NAME)
def test_ticket50232_reverse(topology_st):
"""
The fix for ticket 50232
The test sequence is:
- create suffix
- enable replication before suffix enztry is added
- add suffix entry and some child entries
- get RUV and database generation
- export -r
- import
- get RUV and database generation
- assert database generation has not changed
"""
log.info('Testing Ticket 50232 - export creates not imprtable ldif file, normal creation order')
#
# Setup Replication
#
log.info('Setting up replication...')
repl = ReplicationManager(DEFAULT_SUFFIX)
# repl.create_first_master(topology_st.standalone)
#
# enable dynamic plugins, memberof and retro cl plugin
#
topology_st.standalone.backend.create(REVERSE_SUFFIX, {BACKEND_NAME: REVERSE_BACKEND_NAME})
topology_st.standalone.mappingtree.create(REVERSE_SUFFIX, bename=REVERSE_BACKEND_NAME, parent=None)
_enable_replica(topology_st.standalone, REVERSE_SUFFIX)
_populate_suffix(topology_st.standalone, REVERSE_BACKEND_NAME)
_test_export_import(topology_st.standalone, REVERSE_SUFFIX, REVERSE_BACKEND_NAME)
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
CURRENT_FILE = os.path.realpath(__file__)
pytest.main("-s %s" % CURRENT_FILE)
# --- BEGIN COPYRIGHT BLOCK ---
# Copyright (C) 2019 Red Hat, Inc.
# All rights reserved.
#
# License: GPL (version 3 or any later version).
# See LICENSE for details.
# --- END COPYRIGHT BLOCK ---
#
import logging
import time
import ldap
import pytest
from lib389.topologies import topology_st
from lib389._constants import DEFAULT_SUFFIX
from lib389.idm.user import UserAccount, UserAccounts
from lib389.idm.organizationalunit import OrganizationalUnit
log = logging.getLogger(__name__)
def test_ticket50234(topology_st):
"""
The fix for ticket 50234
The test sequence is:
- create more than 10 entries with objectclass organizational units ou=org{}
- add an Account in one of them, eg below ou=org5
- do searches with search base ou=org5 and search filter "objectclass=organizationalunit"
- a subtree search should return 1 entry, the base entry
- a onelevel search should return no entry
"""
log.info('Testing Ticket 50234 - onelvel search returns not matching entry')
for i in range(1,15):
ou = OrganizationalUnit(topology_st.standalone, "ou=Org{},{}".format(i, DEFAULT_SUFFIX))
ou.create(properties={'ou': 'Org'.format(i)})
properties = {
'uid': 'Jeff Vedder',
'cn': 'Jeff Vedder',
'sn': 'user',
'uidNumber': '1000',
'gidNumber': '2000',
'homeDirectory': '/home/' + 'JeffVedder',
'userPassword': 'password'
}
user = UserAccount(topology_st.standalone, "cn=Jeff Vedder,ou=org5,{}".format(DEFAULT_SUFFIX))
user.create(properties=properties)
# in a subtree search the entry used as search base matches the filter and shoul be returned
ent = topology_st.standalone.getEntry("ou=org5,{}".format(DEFAULT_SUFFIX), ldap.SCOPE_SUBTREE, "(objectclass=organizationalunit)")
# in a onelevel search the only child is an useraccount which does not match the filter
# no entry should be returned, which would cause getEntry to raise an exception we need to handle
found = 1
try:
ent = topology_st.standalone.getEntry("ou=org5,{}".format(DEFAULT_SUFFIX), ldap.SCOPE_ONELEVEL, "(objectclass=organizationalunit)")
except ldap.NO_SUCH_OBJECT:
found = 0
assert (found == 0)
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
CURRENT_FILE = os.path.realpath(__file__)
pytest.main("-s %s" % CURRENT_FILE)
......@@ -241,7 +241,8 @@ if ($decrypt_on_export != 0) { $nsexportdecrypt = "nsExportDecrypt: true\n"; }
$nsprintkey = "";
if ($printkey == 0) { $nsprintkey = "nsPrintKey: false\n"; }
$nsldiffile = "nsFilename: ${ldiffile}\n";
$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsreplica}${nsnobase64}${nsnowrap}${nsnoversion}${nsnouniqueid}${nsuseid2entry}${nsonefile}${nsexportdecrypt}${nsprintkey}${nsldiffile}";
$ttl = "ttl: 86400";
$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsreplica}${nsnobase64}${nsnowrap}${nsnoversion}${nsnouniqueid}${nsuseid2entry}${nsonefile}${nsexportdecrypt}${nsprintkey}${nsldiffile}${ttl}";
print("Exporting to ldif file: ${ldiffile}\n");
$rc = DSUtil::ldapmod($entry, %info);
......
......@@ -192,7 +192,8 @@ $nsmergechunksiz = "nsImportChunkSize: ${mergechunksiz}\n";
$nsgenuniqid = "nsUniqueIdGenerator: ${genuniqid}\n";
$nsuniqidname = "";
if ($uniqidname ne "") { $nsuniqidname = "nsUniqueIdGeneratorNamespace: ${uniqidname}\n"; }
$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsldiffiles}${nsnoattrindexes}${nsimportencrypt}${nsmergechunksiz}${nsgenuniqid}${nsuniqidname}";
$ttl = "ttl: 86400";
$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsldiffiles}${nsnoattrindexes}${nsimportencrypt}${nsmergechunksiz}${nsgenuniqid}${nsuniqidname}${ttl}";
$rc = DSUtil::ldapmod($entry, %info);
......
......@@ -90,7 +90,7 @@ static void automember_task_export_destructor(Slapi_Task *task);
static void automember_task_map_destructor(Slapi_Task *task);
#define DEFAULT_FILE_MODE PR_IRUSR | PR_IWUSR
static uint64_t plugin_do_modify = 1;
static uint64_t plugin_do_modify = 0;
static uint64_t plugin_is_betxn = 0;
/*
......@@ -345,15 +345,14 @@ automember_start(Slapi_PBlock *pb)
}
/* Check and set if we should process modify operations */
plugin_do_modify = 1; /* default is "on" */
if ((slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &plugin_entry) == 0) && plugin_entry){
if ((do_modify = slapi_fetch_attr(plugin_entry, AUTOMEMBER_DO_MODIFY, NULL)) ) {
if (strcasecmp(do_modify, "on") && strcasecmp(do_modify, "off")) {
slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
"automember_start - %s: invalid value \"%s\". Valid values are \"on\" or \"off\". Using default of \"on\"\n",
AUTOMEMBER_DO_MODIFY, do_modify);
} else if (strcasecmp(do_modify, "off") == 0 ){
plugin_do_modify = 0;
} else if (strcasecmp(do_modify, "on") == 0 ){
plugin_do_modify = 1;
}
}
}
......@@ -1629,7 +1628,7 @@ out:
static int
automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char *grouping_attr, char *grouping_value, PRFileDesc *ldif_fd, int add)
{
Slapi_PBlock *mod_pb = slapi_pblock_new();
Slapi_PBlock *mod_pb = NULL;
int result = LDAP_SUCCESS;
LDAPMod mod;
LDAPMod *mods[2];
......@@ -1637,6 +1636,29 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char
char *member_value = NULL;
int freeit = 0;
int rc = 0;
Slapi_DN *group_sdn;
Slapi_Entry *group_entry = NULL;
/* First thing check that the group still exists */
group_sdn = slapi_sdn_new_dn_byval(group_dn);
rc = slapi_search_internal_get_entry(group_sdn, NULL, &group_entry, automember_get_plugin_id());
slapi_sdn_free(&group_sdn);
if (rc != LDAP_SUCCESS || group_entry == NULL) {
if (rc == LDAP_NO_SUCH_OBJECT) {
/* the automember group (default or target) does not exist, just skip this definition */
slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
"automember_update_member_value - group (default or target) does not exist (%s)\n",
group_dn);
rc = 0;
} else {
slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
"automember_update_member_value - group (default or target) can not be retrieved (%s) err=%d\n",
group_dn, rc);
}
slapi_entry_free(group_entry);
return rc;
}
slapi_entry_free(group_entry);
/* If grouping_value is dn, we need to fetch the dn instead. */
if (slapi_attr_type_cmp(grouping_value, "dn", SLAPI_TYPE_CMP_EXACT) == 0) {
......@@ -1686,6 +1708,7 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char
member_value, grouping_attr, group_dn);
}
mod_pb = slapi_pblock_new();
slapi_modify_internal_set_pb(mod_pb, group_dn,
mods, 0, 0, automember_get_plugin_id(), 0);
slapi_modify_internal_pb(mod_pb);
......
......@@ -919,8 +919,7 @@ memberof_postop_modrdn(Slapi_PBlock *pb)
* entry that is being renamed. */
for (i = 0; configCopy.groupattrs && configCopy.groupattrs[i]; i++) {
if (0 == slapi_entry_attr_find(post_e, configCopy.groupattrs[i], &attr)) {
if ((ret = memberof_moddn_attr_list(pb, &configCopy, pre_sdn,
post_sdn, attr) != 0)) {
if ((ret = memberof_moddn_attr_list(pb, &configCopy, pre_sdn, post_sdn, attr)) != 0) {
slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
"memberof_postop_modrdn - Update failed for (%s), error (%d)\n",
slapi_sdn_get_dn(pre_sdn), ret);
......@@ -1720,12 +1719,32 @@ memberof_modop_one_replace_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod_o
replace_mod.mod_values = replace_val;
}
rc = memberof_add_memberof_attr(mods, op_to, config->auto_add_oc);
if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
/* the memberof values to be replaced do not exist
* just add the new values */
if (rc == LDAP_NO_SUCH_ATTRIBUTE || rc == LDAP_TYPE_OR_VALUE_EXISTS) {
if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
/*
* For some reason the new modrdn value is present, so retry
* the delete by itself and ignore the add op by tweaking
* the mod array.
*/
mods[1] = NULL;
rc = memberof_add_memberof_attr(mods, op_to, config->auto_add_oc);
} else {
/*
* The memberof value to be replaced does not exist so just
* add the new value. Shuffle the mod array to apply only
* the add operation.
*/
mods[0] = mods[1];
mods[1] = NULL;
rc = memberof_add_memberof_attr(mods, op_to, config->auto_add_oc);
if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
/*
* The entry already has the expected memberOf value, no
* problem just return success.
*/
rc = LDAP_SUCCESS;
}
}
}
}
}
......
......@@ -2471,6 +2471,11 @@ mep_add_post_op(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_TRACE, MEP_PLUGIN_SUBSYSTEM,
"--> mep_add_post_op\n");
/* Just bail if we aren't ready to service requests yet. */
if (!mep_oktodo(pb)) {
return SLAPI_PLUGIN_SUCCESS;
}
/* Reload config if a config entry was added. */
if ((sdn = mep_get_sdn(pb))) {
if (mep_dn_is_config(sdn)) {
......@@ -2543,6 +2548,11 @@ mep_del_post_op(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_TRACE, MEP_PLUGIN_SUBSYSTEM,
"--> mep_del_post_op\n");
/* Just bail if we aren't ready to service requests yet. */
if (!mep_oktodo(pb)) {
return SLAPI_PLUGIN_SUCCESS;
}
/* Reload config if a config entry was deleted. */
if ((sdn = mep_get_sdn(pb))) {
if (mep_dn_is_config(sdn))
......