From a9cd2ffd227c19a458b27415dedaaf4a6b4778ec Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Thu, 11 Jun 2015 12:28:07 -0400 Subject: [PATCH] Ticket 47921 - indirect cos does not reflect changes in the cos attribute Bug Description: Indirect cos results are incorrectly cached, so any changes to entries that are indirect are not returned to the client. Fix Description: Do not cache the vattr result if it came from a indirect cos definition. https://fedorahosted.org/389/ticket/47921 Reviewed by: ? --- dirsrvtests/tickets/ticket47921_test.py | 155 ++++++++++++++++++++++++++++++++ ldap/servers/plugins/cos/cos_cache.c | 26 ++++-- 2 files changed, 174 insertions(+), 7 deletions(-) create mode 100644 dirsrvtests/tickets/ticket47921_test.py diff --git a/dirsrvtests/tickets/ticket47921_test.py b/dirsrvtests/tickets/ticket47921_test.py new file mode 100644 index 0000000..951d33b --- /dev/null +++ b/dirsrvtests/tickets/ticket47921_test.py @@ -0,0 +1,155 @@ +import os +import sys +import time +import ldap +import logging +import pytest +from lib389 import DirSrv, Entry, tools, tasks +from lib389.tools import DirSrvTools +from lib389._constants import * +from lib389.properties import * +from lib389.tasks import * +from lib389.utils import * + +logging.getLogger(__name__).setLevel(logging.DEBUG) +log = logging.getLogger(__name__) + +installation1_prefix = None + + +class TopologyStandalone(object): + def __init__(self, standalone): + standalone.open() + self.standalone = standalone + + +@pytest.fixture(scope="module") +def topology(request): + global installation1_prefix + if installation1_prefix: + args_instance[SER_DEPLOYED_DIR] = installation1_prefix + + # Creating standalone instance ... + standalone = DirSrv(verbose=False) + args_instance[SER_HOST] = HOST_STANDALONE + args_instance[SER_PORT] = PORT_STANDALONE + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX + args_standalone = args_instance.copy() + standalone.allocate(args_standalone) + instance_standalone = standalone.exists() + if instance_standalone: + standalone.delete() + standalone.create() + standalone.open() + + # Clear out the tmp dir + standalone.clearTmpDir(__file__) + + return TopologyStandalone(standalone) + + +def test_ticket47921(topology): + ''' + Test that indirect cos reflects the current value of the indirect entry + ''' + + INDIRECT_COS_DN = 'cn=cos definition,' + DEFAULT_SUFFIX + MANAGER_DN = 'uid=my manager,ou=people,' + DEFAULT_SUFFIX + USER_DN = 'uid=user,ou=people,' + DEFAULT_SUFFIX + + # Add COS definition + try: + topology.standalone.add_s(Entry((INDIRECT_COS_DN, + {'objectclass': 'top cosSuperDefinition cosIndirectDefinition ldapSubEntry'.split(), + 'cosIndirectSpecifier': 'manager', + 'cosAttribute': 'roomnumber' + }))) + except ldap.LDAPError, e: + log.fatal('Failed to add cos defintion, error: ' + e.message['desc']) + assert False + + # Add manager entry + try: + topology.standalone.add_s(Entry((MANAGER_DN, + {'objectclass': 'top extensibleObject'.split(), + 'uid': 'my manager', + 'roomnumber': '1' + }))) + except ldap.LDAPError, e: + log.fatal('Failed to add manager entry, error: ' + e.message['desc']) + assert False + + # Add user entry + try: + topology.standalone.add_s(Entry((USER_DN, + {'objectclass': 'top person organizationalPerson inetorgperson'.split(), + 'sn': 'last', + 'cn': 'full', + 'givenname': 'mark', + 'uid': 'user', + 'manager': MANAGER_DN + }))) + except ldap.LDAPError, e: + log.fatal('Failed to add manager entry, error: ' + e.message['desc']) + assert False + + # Test COS is working + try: + entry = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, + "uid=user", + ['roomnumber']) + if entry: + if entry[0].getValue('roomnumber') != '1': + log.fatal('COS is not working.') + assert False + else: + log.fatal('Failed to find user entry') + assert False + except ldap.LDAPError, e: + log.error('Failed to search for user entry: ' + e.message['desc']) + assert False + + # Modify manager entry + try: + topology.standalone.modify_s(MANAGER_DN, [(ldap.MOD_REPLACE, 'roomnumber', '2')]) + except ldap.LDAPError, e: + log.error('Failed to modify manager entry: ' + e.message['desc']) + assert False + + # Confirm COS is returning the new value + try: + entry = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, + "uid=user", + ['roomnumber']) + if entry: + if entry[0].getValue('roomnumber') != '2': + log.fatal('COS is not working after manager update.') + assert False + else: + log.fatal('Failed to find user entry') + assert False + except ldap.LDAPError, e: + log.error('Failed to search for user entry: ' + e.message['desc']) + assert False + + log.info('Test complete') + + +def test_ticket47921_final(topology): + topology.standalone.delete() + log.info('Testcase PASSED') + + +def run_isolated(): + global installation1_prefix + installation1_prefix = None + + topo = topology(True) + test_ticket47921(topo) + test_ticket47921_final(topo) + + +if __name__ == '__main__': + run_isolated() + diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c index 7d8e877..fa2b6b5 100644 --- a/ldap/servers/plugins/cos/cos_cache.c +++ b/ldap/servers/plugins/cos/cos_cache.c @@ -284,7 +284,7 @@ void cos_cache_backend_state_change(void *handle, char *be_name, static int cos_cache_vattr_get(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *free_flags, void *hint); static int cos_cache_vattr_compare(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result, int flags, void *hint); static int cos_cache_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags); -static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, Slapi_Value *test_this, int *result, int *ops); +static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, Slapi_Value *test_this, int *result, int *ops, int *indirect_cos); /* compares s2 to s1 starting from end of string until the beginning of either @@ -2096,8 +2096,9 @@ static int cos_cache_attrval_exists(cosAttrValue *pAttrs, const char *val) static int cos_cache_vattr_get(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *free_flags, void *hint) { - int ret = -1; cos_cache *pCache = 0; + int indirect_cos = 0; + int ret = -1; LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_vattr_get\n",0,0,0); @@ -2108,10 +2109,15 @@ static int cos_cache_vattr_get(vattr_sp_handle *handle, vattr_context *c, Slapi_ goto bail; } - ret = cos_cache_query_attr(pCache, c, e, type, results, NULL, NULL, NULL); + ret = cos_cache_query_attr(pCache, c, e, type, results, NULL, NULL, NULL, &indirect_cos); if(ret == 0) { - *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES | SLAPI_VIRTUALATTRS_VALUES_CACHEABLE; + if(indirect_cos){ + /* we can't cache indirect cos */ + *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES; + } else { + *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES | SLAPI_VIRTUALATTRS_VALUES_CACHEABLE; + } *actual_type_name = slapi_ch_strdup(type); *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS; } @@ -2138,7 +2144,7 @@ static int cos_cache_vattr_compare(vattr_sp_handle *handle, vattr_context *c, Sl goto bail; } - ret = cos_cache_query_attr(pCache, c, e, type, NULL, test_this, result, NULL); + ret = cos_cache_query_attr(pCache, c, e, type, NULL, test_this, result, NULL, NULL); cos_cache_release(pCache); @@ -2179,7 +2185,7 @@ static int cos_cache_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e, lastattr = pCache->ppAttrIndex[index]->pAttrName; if(1 == cos_cache_query_attr(pCache, NULL, e, lastattr, NULL, NULL, - NULL, &props)) + NULL, &props, NULL)) { /* entry contains this attr */ vattr_type_thang thang = {0}; @@ -2223,7 +2229,10 @@ bail: overriding and allow the DS logic to pick it up by denying knowledge of attribute */ -static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, Slapi_Value *test_this, int *result, int *props) +static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, + Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, + Slapi_Value *test_this, int *result, int *props, + int *indirect_cos) { int ret = -1; cosCache *pCache = (cosCache*)ptheCache; @@ -2420,6 +2429,9 @@ static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Sl if (cos_cache_follow_pointer( context, (char*)slapi_value_get_string(indirectdn), type, &tmp_vals, test_this, result, pointer_flags) == 0) { + if(indirect_cos){ + *indirect_cos = 1; + } hit = 1; /* If the caller requested values, set them. We need * to append values when we follow multiple pointers DNs. */ -- 1.9.3