[2761] | 1 | From a9cd2ffd227c19a458b27415dedaaf4a6b4778ec Mon Sep 17 00:00:00 2001 |
---|
| 2 | From: Mark Reynolds <mreynolds@redhat.com> |
---|
| 3 | Date: Thu, 11 Jun 2015 12:28:07 -0400 |
---|
| 4 | Subject: [PATCH] Ticket 47921 - indirect cos does not reflect changes in the |
---|
| 5 | cos attribute |
---|
| 6 | |
---|
| 7 | Bug Description: Indirect cos results are incorrectly cached, so any changes |
---|
| 8 | to entries that are indirect are not returned to the client. |
---|
| 9 | |
---|
| 10 | Fix Description: Do not cache the vattr result if it came from a indirect cos |
---|
| 11 | definition. |
---|
| 12 | |
---|
| 13 | https://fedorahosted.org/389/ticket/47921 |
---|
| 14 | |
---|
| 15 | Reviewed by: ? |
---|
| 16 | --- |
---|
| 17 | dirsrvtests/tickets/ticket47921_test.py | 155 ++++++++++++++++++++++++++++++++ |
---|
| 18 | ldap/servers/plugins/cos/cos_cache.c | 26 ++++-- |
---|
| 19 | 2 files changed, 174 insertions(+), 7 deletions(-) |
---|
| 20 | create mode 100644 dirsrvtests/tickets/ticket47921_test.py |
---|
| 21 | |
---|
| 22 | diff --git a/dirsrvtests/tickets/ticket47921_test.py b/dirsrvtests/tickets/ticket47921_test.py |
---|
| 23 | new file mode 100644 |
---|
| 24 | index 0000000..951d33b |
---|
| 25 | --- /dev/null |
---|
| 26 | +++ b/dirsrvtests/tickets/ticket47921_test.py |
---|
| 27 | @@ -0,0 +1,155 @@ |
---|
| 28 | +import os |
---|
| 29 | +import sys |
---|
| 30 | +import time |
---|
| 31 | +import ldap |
---|
| 32 | +import logging |
---|
| 33 | +import pytest |
---|
| 34 | +from lib389 import DirSrv, Entry, tools, tasks |
---|
| 35 | +from lib389.tools import DirSrvTools |
---|
| 36 | +from lib389._constants import * |
---|
| 37 | +from lib389.properties import * |
---|
| 38 | +from lib389.tasks import * |
---|
| 39 | +from lib389.utils import * |
---|
| 40 | + |
---|
| 41 | +logging.getLogger(__name__).setLevel(logging.DEBUG) |
---|
| 42 | +log = logging.getLogger(__name__) |
---|
| 43 | + |
---|
| 44 | +installation1_prefix = None |
---|
| 45 | + |
---|
| 46 | + |
---|
| 47 | +class TopologyStandalone(object): |
---|
| 48 | + def __init__(self, standalone): |
---|
| 49 | + standalone.open() |
---|
| 50 | + self.standalone = standalone |
---|
| 51 | + |
---|
| 52 | + |
---|
| 53 | +@pytest.fixture(scope="module") |
---|
| 54 | +def topology(request): |
---|
| 55 | + global installation1_prefix |
---|
| 56 | + if installation1_prefix: |
---|
| 57 | + args_instance[SER_DEPLOYED_DIR] = installation1_prefix |
---|
| 58 | + |
---|
| 59 | + # Creating standalone instance ... |
---|
| 60 | + standalone = DirSrv(verbose=False) |
---|
| 61 | + args_instance[SER_HOST] = HOST_STANDALONE |
---|
| 62 | + args_instance[SER_PORT] = PORT_STANDALONE |
---|
| 63 | + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE |
---|
| 64 | + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX |
---|
| 65 | + args_standalone = args_instance.copy() |
---|
| 66 | + standalone.allocate(args_standalone) |
---|
| 67 | + instance_standalone = standalone.exists() |
---|
| 68 | + if instance_standalone: |
---|
| 69 | + standalone.delete() |
---|
| 70 | + standalone.create() |
---|
| 71 | + standalone.open() |
---|
| 72 | + |
---|
| 73 | + # Clear out the tmp dir |
---|
| 74 | + standalone.clearTmpDir(__file__) |
---|
| 75 | + |
---|
| 76 | + return TopologyStandalone(standalone) |
---|
| 77 | + |
---|
| 78 | + |
---|
| 79 | +def test_ticket47921(topology): |
---|
| 80 | + ''' |
---|
| 81 | + Test that indirect cos reflects the current value of the indirect entry |
---|
| 82 | + ''' |
---|
| 83 | + |
---|
| 84 | + INDIRECT_COS_DN = 'cn=cos definition,' + DEFAULT_SUFFIX |
---|
| 85 | + MANAGER_DN = 'uid=my manager,ou=people,' + DEFAULT_SUFFIX |
---|
| 86 | + USER_DN = 'uid=user,ou=people,' + DEFAULT_SUFFIX |
---|
| 87 | + |
---|
| 88 | + # Add COS definition |
---|
| 89 | + try: |
---|
| 90 | + topology.standalone.add_s(Entry((INDIRECT_COS_DN, |
---|
| 91 | + {'objectclass': 'top cosSuperDefinition cosIndirectDefinition ldapSubEntry'.split(), |
---|
| 92 | + 'cosIndirectSpecifier': 'manager', |
---|
| 93 | + 'cosAttribute': 'roomnumber' |
---|
| 94 | + }))) |
---|
| 95 | + except ldap.LDAPError, e: |
---|
| 96 | + log.fatal('Failed to add cos defintion, error: ' + e.message['desc']) |
---|
| 97 | + assert False |
---|
| 98 | + |
---|
| 99 | + # Add manager entry |
---|
| 100 | + try: |
---|
| 101 | + topology.standalone.add_s(Entry((MANAGER_DN, |
---|
| 102 | + {'objectclass': 'top extensibleObject'.split(), |
---|
| 103 | + 'uid': 'my manager', |
---|
| 104 | + 'roomnumber': '1' |
---|
| 105 | + }))) |
---|
| 106 | + except ldap.LDAPError, e: |
---|
| 107 | + log.fatal('Failed to add manager entry, error: ' + e.message['desc']) |
---|
| 108 | + assert False |
---|
| 109 | + |
---|
| 110 | + # Add user entry |
---|
| 111 | + try: |
---|
| 112 | + topology.standalone.add_s(Entry((USER_DN, |
---|
| 113 | + {'objectclass': 'top person organizationalPerson inetorgperson'.split(), |
---|
| 114 | + 'sn': 'last', |
---|
| 115 | + 'cn': 'full', |
---|
| 116 | + 'givenname': 'mark', |
---|
| 117 | + 'uid': 'user', |
---|
| 118 | + 'manager': MANAGER_DN |
---|
| 119 | + }))) |
---|
| 120 | + except ldap.LDAPError, e: |
---|
| 121 | + log.fatal('Failed to add manager entry, error: ' + e.message['desc']) |
---|
| 122 | + assert False |
---|
| 123 | + |
---|
| 124 | + # Test COS is working |
---|
| 125 | + try: |
---|
| 126 | + entry = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, |
---|
| 127 | + "uid=user", |
---|
| 128 | + ['roomnumber']) |
---|
| 129 | + if entry: |
---|
| 130 | + if entry[0].getValue('roomnumber') != '1': |
---|
| 131 | + log.fatal('COS is not working.') |
---|
| 132 | + assert False |
---|
| 133 | + else: |
---|
| 134 | + log.fatal('Failed to find user entry') |
---|
| 135 | + assert False |
---|
| 136 | + except ldap.LDAPError, e: |
---|
| 137 | + log.error('Failed to search for user entry: ' + e.message['desc']) |
---|
| 138 | + assert False |
---|
| 139 | + |
---|
| 140 | + # Modify manager entry |
---|
| 141 | + try: |
---|
| 142 | + topology.standalone.modify_s(MANAGER_DN, [(ldap.MOD_REPLACE, 'roomnumber', '2')]) |
---|
| 143 | + except ldap.LDAPError, e: |
---|
| 144 | + log.error('Failed to modify manager entry: ' + e.message['desc']) |
---|
| 145 | + assert False |
---|
| 146 | + |
---|
| 147 | + # Confirm COS is returning the new value |
---|
| 148 | + try: |
---|
| 149 | + entry = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, |
---|
| 150 | + "uid=user", |
---|
| 151 | + ['roomnumber']) |
---|
| 152 | + if entry: |
---|
| 153 | + if entry[0].getValue('roomnumber') != '2': |
---|
| 154 | + log.fatal('COS is not working after manager update.') |
---|
| 155 | + assert False |
---|
| 156 | + else: |
---|
| 157 | + log.fatal('Failed to find user entry') |
---|
| 158 | + assert False |
---|
| 159 | + except ldap.LDAPError, e: |
---|
| 160 | + log.error('Failed to search for user entry: ' + e.message['desc']) |
---|
| 161 | + assert False |
---|
| 162 | + |
---|
| 163 | + log.info('Test complete') |
---|
| 164 | + |
---|
| 165 | + |
---|
| 166 | +def test_ticket47921_final(topology): |
---|
| 167 | + topology.standalone.delete() |
---|
| 168 | + log.info('Testcase PASSED') |
---|
| 169 | + |
---|
| 170 | + |
---|
| 171 | +def run_isolated(): |
---|
| 172 | + global installation1_prefix |
---|
| 173 | + installation1_prefix = None |
---|
| 174 | + |
---|
| 175 | + topo = topology(True) |
---|
| 176 | + test_ticket47921(topo) |
---|
| 177 | + test_ticket47921_final(topo) |
---|
| 178 | + |
---|
| 179 | + |
---|
| 180 | +if __name__ == '__main__': |
---|
| 181 | + run_isolated() |
---|
| 182 | + |
---|
| 183 | diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c |
---|
| 184 | index 7d8e877..fa2b6b5 100644 |
---|
| 185 | --- a/ldap/servers/plugins/cos/cos_cache.c |
---|
| 186 | +++ b/ldap/servers/plugins/cos/cos_cache.c |
---|
| 187 | @@ -284,7 +284,7 @@ void cos_cache_backend_state_change(void *handle, char *be_name, |
---|
| 188 | 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); |
---|
| 189 | 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); |
---|
| 190 | static int cos_cache_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags); |
---|
| 191 | -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); |
---|
| 192 | +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); |
---|
| 193 | |
---|
| 194 | /* |
---|
| 195 | compares s2 to s1 starting from end of string until the beginning of either |
---|
| 196 | @@ -2096,8 +2096,9 @@ static int cos_cache_attrval_exists(cosAttrValue *pAttrs, const char *val) |
---|
| 197 | |
---|
| 198 | 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) |
---|
| 199 | { |
---|
| 200 | - int ret = -1; |
---|
| 201 | cos_cache *pCache = 0; |
---|
| 202 | + int indirect_cos = 0; |
---|
| 203 | + int ret = -1; |
---|
| 204 | |
---|
| 205 | LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_vattr_get\n",0,0,0); |
---|
| 206 | |
---|
| 207 | @@ -2108,10 +2109,15 @@ static int cos_cache_vattr_get(vattr_sp_handle *handle, vattr_context *c, Slapi_ |
---|
| 208 | goto bail; |
---|
| 209 | } |
---|
| 210 | |
---|
| 211 | - ret = cos_cache_query_attr(pCache, c, e, type, results, NULL, NULL, NULL); |
---|
| 212 | + ret = cos_cache_query_attr(pCache, c, e, type, results, NULL, NULL, NULL, &indirect_cos); |
---|
| 213 | if(ret == 0) |
---|
| 214 | { |
---|
| 215 | - *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES | SLAPI_VIRTUALATTRS_VALUES_CACHEABLE; |
---|
| 216 | + if(indirect_cos){ |
---|
| 217 | + /* we can't cache indirect cos */ |
---|
| 218 | + *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES; |
---|
| 219 | + } else { |
---|
| 220 | + *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES | SLAPI_VIRTUALATTRS_VALUES_CACHEABLE; |
---|
| 221 | + } |
---|
| 222 | *actual_type_name = slapi_ch_strdup(type); |
---|
| 223 | *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS; |
---|
| 224 | } |
---|
| 225 | @@ -2138,7 +2144,7 @@ static int cos_cache_vattr_compare(vattr_sp_handle *handle, vattr_context *c, Sl |
---|
| 226 | goto bail; |
---|
| 227 | } |
---|
| 228 | |
---|
| 229 | - ret = cos_cache_query_attr(pCache, c, e, type, NULL, test_this, result, NULL); |
---|
| 230 | + ret = cos_cache_query_attr(pCache, c, e, type, NULL, test_this, result, NULL, NULL); |
---|
| 231 | |
---|
| 232 | cos_cache_release(pCache); |
---|
| 233 | |
---|
| 234 | @@ -2179,7 +2185,7 @@ static int cos_cache_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e, |
---|
| 235 | lastattr = pCache->ppAttrIndex[index]->pAttrName; |
---|
| 236 | |
---|
| 237 | if(1 == cos_cache_query_attr(pCache, NULL, e, lastattr, NULL, NULL, |
---|
| 238 | - NULL, &props)) |
---|
| 239 | + NULL, &props, NULL)) |
---|
| 240 | { |
---|
| 241 | /* entry contains this attr */ |
---|
| 242 | vattr_type_thang thang = {0}; |
---|
| 243 | @@ -2223,7 +2229,10 @@ bail: |
---|
| 244 | overriding and allow the DS logic to pick it up by denying knowledge |
---|
| 245 | of attribute |
---|
| 246 | */ |
---|
| 247 | -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) |
---|
| 248 | +static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, |
---|
| 249 | + Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, |
---|
| 250 | + Slapi_Value *test_this, int *result, int *props, |
---|
| 251 | + int *indirect_cos) |
---|
| 252 | { |
---|
| 253 | int ret = -1; |
---|
| 254 | cosCache *pCache = (cosCache*)ptheCache; |
---|
| 255 | @@ -2420,6 +2429,9 @@ static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Sl |
---|
| 256 | if (cos_cache_follow_pointer( context, (char*)slapi_value_get_string(indirectdn), |
---|
| 257 | type, &tmp_vals, test_this, result, pointer_flags) == 0) |
---|
| 258 | { |
---|
| 259 | + if(indirect_cos){ |
---|
| 260 | + *indirect_cos = 1; |
---|
| 261 | + } |
---|
| 262 | hit = 1; |
---|
| 263 | /* If the caller requested values, set them. We need |
---|
| 264 | * to append values when we follow multiple pointers DNs. */ |
---|
| 265 | -- |
---|
| 266 | 1.9.3 |
---|
| 267 | |
---|