andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From 056d9a6e679696422b1fa686d03a60657b77565b Mon Sep 17 00:00:00 2001
dc8c34
From: Mark Reynolds <mreynolds@redhat.com>
dc8c34
Date: Mon, 5 Jan 2015 16:56:09 -0500
dc8c34
Subject: [PATCH 287/305] Ticket 47980 - Nested COS definitions can be
dc8c34
 incorrectly  processed
dc8c34
dc8c34
Bug Description:  The COS cache attribute index gets incorrectly sorted
dc8c34
                  and results in unexpected COS values being applied to
dc8c34
                  an entry.
dc8c34
dc8c34
Fix Description:  The sorting method for comparing the target tree does
dc8c34
                  not work as indended, but we don't need to sort by the
dc8c34
                  target tree if the cos attributes are the same, as the
dc8c34
                  list is already in the proper tree order as returned by
dc8c34
                  the internal search.  The fix was just to remove the
dc8c34
                  target tree comparison from the qsort compare function.
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/47980
dc8c34
dc8c34
Reviewed by: nhosoi(Thanks!)
dc8c34
dc8c34
(cherry picked from commit 987580d6fb42e358d84539a78879ae9a00393bd1)
dc8c34
(cherry picked from commit 322d7d0dabb0b3cf52a0c544f0e4fb09e9af9080)
dc8c34
---
dc8c34
 dirsrvtests/tickets/ticket47980_test.py | 710 ++++++++++++++++++++++++++++++++
dc8c34
 ldap/servers/plugins/cos/cos_cache.c    |  20 +-
dc8c34
 2 files changed, 717 insertions(+), 13 deletions(-)
dc8c34
 create mode 100644 dirsrvtests/tickets/ticket47980_test.py
dc8c34
dc8c34
diff --git a/dirsrvtests/tickets/ticket47980_test.py b/dirsrvtests/tickets/ticket47980_test.py
dc8c34
new file mode 100644
dc8c34
index 0000000..406d72d
dc8c34
--- /dev/null
dc8c34
+++ b/dirsrvtests/tickets/ticket47980_test.py
dc8c34
@@ -0,0 +1,710 @@
dc8c34
+import os
dc8c34
+import sys
dc8c34
+import time
dc8c34
+import ldap
dc8c34
+import ldap.sasl
dc8c34
+import logging
dc8c34
+import socket
dc8c34
+import pytest
dc8c34
+from lib389 import DirSrv, Entry, tools, tasks
dc8c34
+from lib389.tools import DirSrvTools
dc8c34
+from lib389._constants import *
dc8c34
+from lib389.properties import *
dc8c34
+from lib389.tasks import *
dc8c34
+from constants import *
dc8c34
+
dc8c34
+log = logging.getLogger(__name__)
dc8c34
+
dc8c34
+installation_prefix = None
dc8c34
+
dc8c34
+BRANCH1 = 'ou=level1,' + DEFAULT_SUFFIX
dc8c34
+BRANCH2 = 'ou=level2,ou=level1,' + DEFAULT_SUFFIX
dc8c34
+BRANCH3 = 'ou=level3,ou=level2,ou=level1,' + DEFAULT_SUFFIX
dc8c34
+BRANCH4 = 'ou=people,' + DEFAULT_SUFFIX
dc8c34
+BRANCH5 = 'ou=lower,ou=people,' + DEFAULT_SUFFIX
dc8c34
+BRANCH6 = 'ou=lower,ou=lower,ou=people,' + DEFAULT_SUFFIX
dc8c34
+USER1_DN = 'uid=user1,%s' % (BRANCH1)
dc8c34
+USER2_DN = 'uid=user2,%s' % (BRANCH2)
dc8c34
+USER3_DN = 'uid=user3,%s' % (BRANCH3)
dc8c34
+USER4_DN = 'uid=user4,%s' % (BRANCH4)
dc8c34
+USER5_DN = 'uid=user5,%s' % (BRANCH5)
dc8c34
+USER6_DN = 'uid=user6,%s' % (BRANCH6)
dc8c34
+
dc8c34
+BRANCH1_CONTAINER = 'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
dc8c34
+BRANCH1_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+                  'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
dc8c34
+BRANCH1_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+                  'cn=nsPwPolicyContainer,ou=level1,dc=example,dc=com'
dc8c34
+BRANCH1_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level1,dc=example,dc=com'
dc8c34
+
dc8c34
+BRANCH2_CONTAINER = 'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
dc8c34
+BRANCH2_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+             'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
dc8c34
+BRANCH2_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+                  'cn=nsPwPolicyContainer,ou=level2,ou=level1,dc=example,dc=com'
dc8c34
+BRANCH2_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level2,ou=level1,dc=example,dc=com'
dc8c34
+
dc8c34
+BRANCH3_CONTAINER = 'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
dc8c34
+BRANCH3_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlevel3\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+             'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
dc8c34
+BRANCH3_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlevel3\2Cou\3Dlevel2\2Cou\3Dlevel1\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+                  'cn=nsPwPolicyContainer,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
dc8c34
+BRANCH3_COS_DEF = 'cn=nsPwPolicy_CoS,ou=level3,ou=level2,ou=level1,dc=example,dc=com'
dc8c34
+
dc8c34
+BRANCH4_CONTAINER = 'cn=nsPwPolicyContainer,ou=people,dc=example,dc=com'
dc8c34
+BRANCH4_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+             'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
dc8c34
+BRANCH4_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+                  'cn=nsPwPolicyContainer,ou=People,dc=example,dc=com'
dc8c34
+BRANCH4_COS_DEF = 'cn=nsPwPolicy_CoS,ou=people,dc=example,dc=com'
dc8c34
+
dc8c34
+BRANCH5_CONTAINER = 'cn=nsPwPolicyContainer,ou=lower,ou=people,dc=example,dc=com'
dc8c34
+BRANCH5_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+             'cn=nsPwPolicyContainer,ou=lower,ou=People,dc=example,dc=com'
dc8c34
+BRANCH5_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+                  'cn=nsPwPolicyContainer,ou=lower,ou=People,dc=example,dc=com'
dc8c34
+BRANCH5_COS_DEF = 'cn=nsPwPolicy_CoS,ou=lower,ou=People,dc=example,dc=com'
dc8c34
+
dc8c34
+BRANCH6_CONTAINER = 'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
dc8c34
+BRANCH6_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cou\3Dlower\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+             'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
dc8c34
+BRANCH6_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cou\3Dlower\2Cou\3Dlower\2Cou\3DPeople\2Cdc\3Dexample\2Cdc\3Dcom,' + \
dc8c34
+                  'cn=nsPwPolicyContainer,ou=lower,ou=lower,ou=People,dc=example,dc=com'
dc8c34
+BRANCH6_COS_DEF = 'cn=nsPwPolicy_CoS,ou=lower,ou=lower,ou=People,dc=example,dc=com'
dc8c34
+
dc8c34
+
dc8c34
+class TopologyStandalone(object):
dc8c34
+    def __init__(self, standalone):
dc8c34
+        standalone.open()
dc8c34
+        self.standalone = standalone
dc8c34
+
dc8c34
+
dc8c34
+@pytest.fixture(scope="module")
dc8c34
+def topology(request):
dc8c34
+    '''
dc8c34
+        This fixture is used to standalone topology for the 'module'.
dc8c34
+        At the beginning, It may exists a standalone instance.
dc8c34
+        It may also exists a backup for the standalone instance.
dc8c34
+
dc8c34
+        Principle:
dc8c34
+            If standalone instance exists:
dc8c34
+                restart it
dc8c34
+            If backup of standalone exists:
dc8c34
+                create/rebind to standalone
dc8c34
+
dc8c34
+                restore standalone instance from backup
dc8c34
+            else:
dc8c34
+                Cleanup everything
dc8c34
+                    remove instance
dc8c34
+                    remove backup
dc8c34
+                Create instance
dc8c34
+                Create backup
dc8c34
+    '''
dc8c34
+    global installation_prefix
dc8c34
+
dc8c34
+    if installation_prefix:
dc8c34
+        args_instance[SER_DEPLOYED_DIR] = installation_prefix
dc8c34
+
dc8c34
+    standalone = DirSrv(verbose=False)
dc8c34
+
dc8c34
+    # Args for the standalone instance
dc8c34
+    args_instance[SER_HOST] = HOST_STANDALONE
dc8c34
+    args_instance[SER_PORT] = PORT_STANDALONE
dc8c34
+    args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
dc8c34
+    args_standalone = args_instance.copy()
dc8c34
+    standalone.allocate(args_standalone)
dc8c34
+
dc8c34
+    # Get the status of the backups
dc8c34
+    backup_standalone = standalone.checkBackupFS()
dc8c34
+
dc8c34
+    # Get the status of the instance and restart it if it exists
dc8c34
+    instance_standalone = standalone.exists()
dc8c34
+    if instance_standalone:
dc8c34
+        # assuming the instance is already stopped, just wait 5 sec max
dc8c34
+        standalone.stop(timeout=5)
dc8c34
+        standalone.start(timeout=10)
dc8c34
+
dc8c34
+    if backup_standalone:
dc8c34
+        # The backup exist, assuming it is correct
dc8c34
+        # we just re-init the instance with it
dc8c34
+        if not instance_standalone:
dc8c34
+            standalone.create()
dc8c34
+            # Used to retrieve configuration information (dbdir, confdir...)
dc8c34
+            standalone.open()
dc8c34
+
dc8c34
+        # restore standalone instance from backup
dc8c34
+        standalone.stop(timeout=10)
dc8c34
+        standalone.restoreFS(backup_standalone)
dc8c34
+        standalone.start(timeout=10)
dc8c34
+
dc8c34
+    else:
dc8c34
+        # We should be here only in two conditions
dc8c34
+        #      - This is the first time a test involve standalone instance
dc8c34
+        #      - Something weird happened (instance/backup destroyed)
dc8c34
+        #        so we discard everything and recreate all
dc8c34
+
dc8c34
+        # Remove the backup. So even if we have a specific backup file
dc8c34
+        # (e.g backup_standalone) we clear backup that an instance may have created
dc8c34
+        if backup_standalone:
dc8c34
+            standalone.clearBackupFS()
dc8c34
+
dc8c34
+        # Remove the instance
dc8c34
+        if instance_standalone:
dc8c34
+            standalone.delete()
dc8c34
+
dc8c34
+        # Create the instance
dc8c34
+        standalone.create()
dc8c34
+
dc8c34
+        # Used to retrieve configuration information (dbdir, confdir...)
dc8c34
+        standalone.open()
dc8c34
+
dc8c34
+        # Time to create the backups
dc8c34
+        standalone.stop(timeout=10)
dc8c34
+        standalone.backupfile = standalone.backupFS()
dc8c34
+        standalone.start(timeout=10)
dc8c34
+
dc8c34
+    # clear the tmp directory
dc8c34
+    standalone.clearTmpDir(__file__)
dc8c34
+
dc8c34
+    #
dc8c34
+    # Here we have standalone instance up and running
dc8c34
+    # Either coming from a backup recovery
dc8c34
+    # or from a fresh (re)init
dc8c34
+    # Time to return the topology
dc8c34
+    return TopologyStandalone(standalone)
dc8c34
+
dc8c34
+
dc8c34
+def test_ticket47980(topology):
dc8c34
+    """
dc8c34
+        Multiple COS pointer definitions that use the same attribute are not correctly ordered.
dc8c34
+        The cos plugin was incorrectly sorting the attribute indexes based on subtree, which lead
dc8c34
+        to the wrong cos attribute value being applied to the entry.
dc8c34
+    """
dc8c34
+
dc8c34
+    log.info('Testing Ticket 47980 - Testing multiple nested COS pointer definitions are processed correctly')
dc8c34
+
dc8c34
+    # Add our nested branches
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH1, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'ou': 'level1'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add level1: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH2, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'ou': 'level2'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add level2: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH3, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'uid': 'level3'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add level3: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # People branch, might already exist
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH4, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'ou': 'level4'
dc8c34
+                          })))
dc8c34
+    except ldap.ALREADY_EXISTS:
dc8c34
+        pass
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add level4: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH5, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'ou': 'level5'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add level5: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH6, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'uid': 'level6'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add level6: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add users to each branch
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((USER1_DN, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'uid': 'user1'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add user1: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((USER2_DN, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'uid': 'user2'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add user2: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((USER3_DN, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'uid': 'user3'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add user3: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((USER4_DN, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'uid': 'user4'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add user4: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((USER5_DN, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'uid': 'user5'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add user5: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((USER6_DN, {
dc8c34
+                          'objectclass': 'top extensibleObject'.split(),
dc8c34
+                          'uid': 'user6'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add user6: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Enable password policy
dc8c34
+    try:
dc8c34
+        topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    #
dc8c34
+    # Add subtree policy to branch 1
dc8c34
+    #
dc8c34
+    # Add the container
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH1_CONTAINER, {
dc8c34
+                          'objectclass': 'top nsContainer'.split(),
dc8c34
+                          'cn': 'nsPwPolicyContainer'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add subtree container for level1: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the password policy subentry
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH1_PWP, {
dc8c34
+                          'objectclass': 'top ldapsubentry passwordpolicy'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
dc8c34
+                          'passwordMustChange': 'off',
dc8c34
+                          'passwordExp': 'off',
dc8c34
+                          'passwordHistory': 'off',
dc8c34
+                          'passwordMinAge': '0',
dc8c34
+                          'passwordChange': 'off',
dc8c34
+                          'passwordStorageScheme': 'ssha'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add passwordpolicy for level1: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS template
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH1_COS_TMPL, {
dc8c34
+                          'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
dc8c34
+                          'cosPriority': '1',
dc8c34
+                          'cn': 'cn=nsPwTemplateEntry,ou=level1,dc=example,dc=com',
dc8c34
+                          'pwdpolicysubentry': BRANCH1_PWP
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS template for level1: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS definition
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH1_COS_DEF, {
dc8c34
+                          'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=level1,dc=example,dc=com',
dc8c34
+                          'costemplatedn': BRANCH1_COS_TMPL,
dc8c34
+                          'cosAttribute': 'pwdpolicysubentry default operational-default'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS def for level1: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    #
dc8c34
+    # Add subtree policy to branch 2
dc8c34
+    #
dc8c34
+    # Add the container
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH2_CONTAINER, {
dc8c34
+                          'objectclass': 'top nsContainer'.split(),
dc8c34
+                          'cn': 'nsPwPolicyContainer'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add subtree container for level2: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the password policy subentry
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH2_PWP, {
dc8c34
+                          'objectclass': 'top ldapsubentry passwordpolicy'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
dc8c34
+                          'passwordMustChange': 'off',
dc8c34
+                          'passwordExp': 'off',
dc8c34
+                          'passwordHistory': 'off',
dc8c34
+                          'passwordMinAge': '0',
dc8c34
+                          'passwordChange': 'off',
dc8c34
+                          'passwordStorageScheme': 'ssha'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add passwordpolicy for level2: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS template
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH2_COS_TMPL, {
dc8c34
+                          'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
dc8c34
+                          'cosPriority': '1',
dc8c34
+                          'cn': 'cn=nsPwTemplateEntry,ou=level2,dc=example,dc=com',
dc8c34
+                          'pwdpolicysubentry': BRANCH2_PWP
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS template for level2: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS definition
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH2_COS_DEF, {
dc8c34
+                          'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=level2,dc=example,dc=com',
dc8c34
+                          'costemplatedn': BRANCH2_COS_TMPL,
dc8c34
+                          'cosAttribute': 'pwdpolicysubentry default operational-default'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS def for level2: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    #
dc8c34
+    # Add subtree policy to branch 3
dc8c34
+    #
dc8c34
+    # Add the container
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH3_CONTAINER, {
dc8c34
+                          'objectclass': 'top nsContainer'.split(),
dc8c34
+                          'cn': 'nsPwPolicyContainer'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add subtree container for level3: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the password policy subentry
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH3_PWP, {
dc8c34
+                          'objectclass': 'top ldapsubentry passwordpolicy'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
dc8c34
+                          'passwordMustChange': 'off',
dc8c34
+                          'passwordExp': 'off',
dc8c34
+                          'passwordHistory': 'off',
dc8c34
+                          'passwordMinAge': '0',
dc8c34
+                          'passwordChange': 'off',
dc8c34
+                          'passwordStorageScheme': 'ssha'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add passwordpolicy for level3: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS template
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH3_COS_TMPL, {
dc8c34
+                          'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
dc8c34
+                          'cosPriority': '1',
dc8c34
+                          'cn': 'cn=nsPwTemplateEntry,ou=level3,dc=example,dc=com',
dc8c34
+                          'pwdpolicysubentry': BRANCH3_PWP
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS template for level3: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS definition
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH3_COS_DEF, {
dc8c34
+                          'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
dc8c34
+                          'costemplatedn': BRANCH3_COS_TMPL,
dc8c34
+                          'cosAttribute': 'pwdpolicysubentry default operational-default'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS def for level3: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    #
dc8c34
+    # Add subtree policy to branch 4
dc8c34
+    #
dc8c34
+    # Add the container
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH4_CONTAINER, {
dc8c34
+                          'objectclass': 'top nsContainer'.split(),
dc8c34
+                          'cn': 'nsPwPolicyContainer'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add subtree container for level3: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the password policy subentry
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH4_PWP, {
dc8c34
+                          'objectclass': 'top ldapsubentry passwordpolicy'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
dc8c34
+                          'passwordMustChange': 'off',
dc8c34
+                          'passwordExp': 'off',
dc8c34
+                          'passwordHistory': 'off',
dc8c34
+                          'passwordMinAge': '0',
dc8c34
+                          'passwordChange': 'off',
dc8c34
+                          'passwordStorageScheme': 'ssha'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add passwordpolicy for branch4: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS template
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH4_COS_TMPL, {
dc8c34
+                          'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
dc8c34
+                          'cosPriority': '1',
dc8c34
+                          'cn': 'cn=nsPwTemplateEntry,ou=people,dc=example,dc=com',
dc8c34
+                          'pwdpolicysubentry': BRANCH4_PWP
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS template for level3: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS definition
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH4_COS_DEF, {
dc8c34
+                          'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=people,dc=example,dc=com',
dc8c34
+                          'costemplatedn': BRANCH4_COS_TMPL,
dc8c34
+                          'cosAttribute': 'pwdpolicysubentry default operational-default'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS def for branch4: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    #
dc8c34
+    # Add subtree policy to branch 5
dc8c34
+    #
dc8c34
+    # Add the container
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH5_CONTAINER, {
dc8c34
+                          'objectclass': 'top nsContainer'.split(),
dc8c34
+                          'cn': 'nsPwPolicyContainer'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add subtree container for branch5: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the password policy subentry
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH5_PWP, {
dc8c34
+                          'objectclass': 'top ldapsubentry passwordpolicy'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
dc8c34
+                          'passwordMustChange': 'off',
dc8c34
+                          'passwordExp': 'off',
dc8c34
+                          'passwordHistory': 'off',
dc8c34
+                          'passwordMinAge': '0',
dc8c34
+                          'passwordChange': 'off',
dc8c34
+                          'passwordStorageScheme': 'ssha'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add passwordpolicy for branch5: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS template
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH5_COS_TMPL, {
dc8c34
+                          'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
dc8c34
+                          'cosPriority': '1',
dc8c34
+                          'cn': 'cn=nsPwTemplateEntry,ou=lower,ou=people,dc=example,dc=com',
dc8c34
+                          'pwdpolicysubentry': BRANCH5_PWP
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS template for branch5: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS definition
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH5_COS_DEF, {
dc8c34
+                          'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=people,dc=example,dc=com',
dc8c34
+                          'costemplatedn': BRANCH5_COS_TMPL,
dc8c34
+                          'cosAttribute': 'pwdpolicysubentry default operational-default'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS def for level3: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    #
dc8c34
+    # Add subtree policy to branch 6
dc8c34
+    #
dc8c34
+    # Add the container
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH6_CONTAINER, {
dc8c34
+                          'objectclass': 'top nsContainer'.split(),
dc8c34
+                          'cn': 'nsPwPolicyContainer'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add subtree container for branch6: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the password policy subentry
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH6_PWP, {
dc8c34
+                          'objectclass': 'top ldapsubentry passwordpolicy'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=level3,dc=example,dc=com',
dc8c34
+                          'passwordMustChange': 'off',
dc8c34
+                          'passwordExp': 'off',
dc8c34
+                          'passwordHistory': 'off',
dc8c34
+                          'passwordMinAge': '0',
dc8c34
+                          'passwordChange': 'off',
dc8c34
+                          'passwordStorageScheme': 'ssha'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add passwordpolicy for branch6: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS template
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH6_COS_TMPL, {
dc8c34
+                          'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
dc8c34
+                          'cosPriority': '1',
dc8c34
+                          'cn': 'cn=nsPwTemplateEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
dc8c34
+                          'pwdpolicysubentry': BRANCH6_PWP
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS template for branch6: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # Add the COS definition
dc8c34
+    try:
dc8c34
+        topology.standalone.add_s(Entry((BRANCH6_COS_DEF, {
dc8c34
+                          'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
dc8c34
+                          'cn': 'cn=nsPwPolicyEntry,ou=lower,ou=lower,ou=people,dc=example,dc=com',
dc8c34
+                          'costemplatedn': BRANCH6_COS_TMPL,
dc8c34
+                          'cosAttribute': 'pwdpolicysubentry default operational-default'
dc8c34
+                          })))
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.error('Failed to add COS def for branch6: error ' + e.message['desc'])
dc8c34
+        assert False
dc8c34
+
dc8c34
+    #
dc8c34
+    # Now check that each user has its expected passwordPolicy subentry
dc8c34
+    #
dc8c34
+    try:
dc8c34
+        entries = topology.standalone.search_s(USER1_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
dc8c34
+        if not entries[0].hasValue('pwdpolicysubentry', BRANCH1_PWP):
dc8c34
+            log.fatal('User %s does not have expected pwdpolicysubentry!')
dc8c34
+            assert False
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.fatal('Unable to search for entry %s: error %s' % (USER1_DN, e.message['desc']))
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        entries = topology.standalone.search_s(USER2_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
dc8c34
+        if not entries[0].hasValue('pwdpolicysubentry', BRANCH2_PWP):
dc8c34
+            log.fatal('User %s does not have expected pwdpolicysubentry!' % USER2_DN)
dc8c34
+            assert False
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.fatal('Unable to search for entry %s: error %s' % (USER2_DN, e.message['desc']))
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        entries = topology.standalone.search_s(USER3_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
dc8c34
+        if not entries[0].hasValue('pwdpolicysubentry', BRANCH3_PWP):
dc8c34
+            log.fatal('User %s does not have expected pwdpolicysubentry!' % USER3_DN)
dc8c34
+            assert False
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.fatal('Unable to search for entry %s: error %s' % (USER3_DN, e.message['desc']))
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        entries = topology.standalone.search_s(USER4_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
dc8c34
+        if not entries[0].hasValue('pwdpolicysubentry', BRANCH4_PWP):
dc8c34
+            log.fatal('User %s does not have expected pwdpolicysubentry!' % USER4_DN)
dc8c34
+            assert False
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.fatal('Unable to search for entry %s: error %s' % (USER4_DN, e.message['desc']))
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        entries = topology.standalone.search_s(USER5_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
dc8c34
+        if not entries[0].hasValue('pwdpolicysubentry', BRANCH5_PWP):
dc8c34
+            log.fatal('User %s does not have expected pwdpolicysubentry!' % USER5_DN)
dc8c34
+            assert False
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.fatal('Unable to search for entry %s: error %s' % (USER5_DN, e.message['desc']))
dc8c34
+        assert False
dc8c34
+
dc8c34
+    try:
dc8c34
+        entries = topology.standalone.search_s(USER6_DN, ldap.SCOPE_BASE, '(objectclass=top)', ['pwdpolicysubentry'])
dc8c34
+        if not entries[0].hasValue('pwdpolicysubentry', BRANCH6_PWP):
dc8c34
+            log.fatal('User %s does not have expected pwdpolicysubentry!' % USER6_DN)
dc8c34
+            assert False
dc8c34
+    except ldap.LDAPError, e:
dc8c34
+        log.fatal('Unable to search for entry %s: error %s' % (USER6_DN, e.message['desc']))
dc8c34
+        assert False
dc8c34
+
dc8c34
+    # If we got here the test passed
dc8c34
+    log.info('Test PASSED')
dc8c34
+
dc8c34
+
dc8c34
+def test_ticket47980_final(topology):
dc8c34
+    topology.standalone.stop(timeout=10)
dc8c34
+
dc8c34
+
dc8c34
+def run_isolated():
dc8c34
+    '''
dc8c34
+        run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
dc8c34
+        To run isolated without py.test, you need to
dc8c34
+            - edit this file and comment '@pytest.fixture' line before 'topology' function.
dc8c34
+            - set the installation prefix
dc8c34
+            - run this program
dc8c34
+    '''
dc8c34
+    global installation_prefix
dc8c34
+    installation_prefix = None
dc8c34
+
dc8c34
+    topo = topology(True)
dc8c34
+    test_ticket47980(topo)
dc8c34
+
dc8c34
+if __name__ == '__main__':
dc8c34
+    run_isolated()
dc8c34
\ No newline at end of file
dc8c34
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
dc8c34
index 10f475e..76cc8fd 100644
dc8c34
--- a/ldap/servers/plugins/cos/cos_cache.c
dc8c34
+++ b/ldap/servers/plugins/cos/cos_cache.c
dc8c34
@@ -3097,25 +3097,19 @@ static int cos_cache_attr_compare(const void *e1, const void *e2)
dc8c34
 	int com_Result;
dc8c34
 	cosAttributes *pAttr = (*(cosAttributes**)e1);
dc8c34
 	cosTemplates *pTemplate = (cosTemplates*)pAttr->pParent;
dc8c34
-    cosDefinitions *pDef = (cosDefinitions*)pTemplate->pParent;
dc8c34
-	cosAttrValue *pcostt = pDef->pCosTargetTree;
dc8c34
 	cosAttributes *pAttr1 = (*(cosAttributes**)e2);
dc8c34
 	cosTemplates *pTemplate1 = (cosTemplates*)pAttr1->pParent;
dc8c34
-	cosDefinitions *pDef1 = (cosDefinitions*)pTemplate1->pParent;
dc8c34
-    cosAttrValue *pcostt1 = pDef1->pCosTargetTree;
dc8c34
         
dc8c34
 	/* Now compare the names of the attributes */
dc8c34
 	com_Result = slapi_utf8casecmp((unsigned char*)(*(cosAttributes**)e1)->pAttrName,(unsigned char*)(*(cosAttributes**)e2)->pAttrName);
dc8c34
+	if(0 == com_Result){
dc8c34
+		/* Now compare the cosPriorities */
dc8c34
+		com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
dc8c34
+	}
dc8c34
 	if(0 == com_Result)
dc8c34
-	/* Now compare the definition Dn parents */
dc8c34
-      com_Result = slapi_utf8casecmp((unsigned char*)pcostt1->val,(unsigned char*)pcostt->val);   
dc8c34
-	  if(0 == com_Result)
dc8c34
-	/* Now compare the cosPririoties */     
dc8c34
-	     com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
dc8c34
-	/* Now compare the prirority */ 
dc8c34
-		  if(0 == com_Result)
dc8c34
-	            return -1;   
dc8c34
-		  return com_Result;
dc8c34
+		return -1;
dc8c34
+
dc8c34
+	return com_Result;
dc8c34
 }
dc8c34
 
dc8c34
 static int cos_cache_string_compare(const void *e1, const void *e2)
dc8c34
-- 
dc8c34
1.9.3
dc8c34