From c7d80cc5fc929599759153b2fa0da64dfcf2f783 Mon Sep 17 00:00:00 2001 From: Ludwig Krispenz Date: Wed, 25 May 2016 15:26:27 +0200 Subject: [PATCH 2/2] testcase for ticket 48275 --- dirsrvtests/tests/tickets/ticket48275_test.py | 338 ++++++++++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 dirsrvtests/tests/tickets/ticket48275_test.py diff --git a/dirsrvtests/tests/tickets/ticket48275_test.py b/dirsrvtests/tests/tickets/ticket48275_test.py new file mode 100644 index 0000000..ccaa6dc --- /dev/null +++ b/dirsrvtests/tests/tickets/ticket48275_test.py @@ -0,0 +1,338 @@ +# --- BEGIN COPYRIGHT BLOCK --- +# Copyright (C) 2015 Red Hat, Inc. +# All rights reserved. +# +# License: GPL (version 3 or any later version). +# See LICENSE for details. +# --- END COPYRIGHT BLOCK --- +# +import os +import sys +import time +import ldap +import logging +import pytest +from lib389 import DirSrv, Entry, tools +from lib389.tools import DirSrvTools +from lib389._constants import * +from lib389.properties import * + +log = logging.getLogger(__name__) + +installation_prefix = None + +USER_NUM = 10 +TEST_USER = 'user' + +OTHER_NAME = 'other_entry' +MAX_OTHERS = 10 + +BIND_NAME = 'bind_entry' +BIND_DN = 'cn=%s, %s' % (BIND_NAME, SUFFIX) +BIND_PW = 'password' + +ENTRY_NAME = 'test_entry' +ENTRY_DN = 'cn=%s, %s' % (ENTRY_NAME, SUFFIX) +ENTRY_OC = "top person" + +# subtrees used in test +SUBTREE_BASE = "ou=testbase,%s" %SUFFIX +SUBTREE_GREEN_1 = "ou=green_one,%s" % SUBTREE_BASE +SUBTREE_GREEN_2 = "ou=green_two,%s" % SUBTREE_BASE +SUBTREE_RED = "ou=red,%s" % SUBTREE_BASE +SUBTREES = (SUBTREE_GREEN_1, SUBTREE_GREEN_2, SUBTREE_RED) + +class TopologyStandalone(object): + def __init__(self, standalone): + standalone.open() + self.standalone = standalone + + +@pytest.fixture(scope="module") +def topology(request): + global installation_prefix + + if installation_prefix: + args_instance[SER_DEPLOYED_DIR] = installation_prefix + + standalone = DirSrv(verbose=False) + + # Args for the standalone instance + args_instance[SER_HOST] = HOST_STANDALONE + args_instance[SER_PORT] = PORT_STANDALONE + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE + args_standalone = args_instance.copy() + standalone.allocate(args_standalone) + + # Get the status of the instance and restart it if it exists + instance_standalone = standalone.exists() + + # Remove the instance + if instance_standalone: + standalone.delete() + + # Create the instance + standalone.create() + + # Used to retrieve configuration information (dbdir, confdir...) + standalone.open() + + # clear the tmp directory + standalone.clearTmpDir(__file__) + + # Here we have standalone instance up and running + return TopologyStandalone(standalone) + + +def test_ticket48275_init(topology): + """ + It creates identical entries in 3 subtrees + It creates aci which allow access to a set of attrs + in two of these subtrees for bound users + It creates a user to be used for test + + """ + + + topology.standalone.log.info("Add subtree base: %s" % SUBTREE_BASE) + topology.standalone.add_s(Entry((SUBTREE_BASE, { + 'objectclass': "top organizationalunit".split(), + 'ou': "testbase"}))) + topology.standalone.log.info("Add subtree: %s" % SUBTREE_GREEN_1) + topology.standalone.add_s(Entry((SUBTREE_GREEN_1, { + 'objectclass': "top organizationalunit".split(), + 'ou': "green_one"}))) + topology.standalone.log.info("Add subtree: %s" % SUBTREE_GREEN_2) + topology.standalone.add_s(Entry((SUBTREE_GREEN_2, { + 'objectclass': "top organizationalunit".split(), + 'ou': "green_two"}))) + topology.standalone.log.info("Add subtree: %s" % SUBTREE_RED) + topology.standalone.add_s(Entry((SUBTREE_RED, { + 'objectclass': "top organizationalunit".split(), + 'ou': "red"}))) + + # entry used to bind with + topology.standalone.log.info("Add %s" % BIND_DN) + topology.standalone.add_s(Entry((BIND_DN, { + 'objectclass': "top person".split(), + 'sn': BIND_NAME, + 'cn': BIND_NAME, + 'userpassword': BIND_PW}))) + + # enable acl error logging + # mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '128')] + # topology.standalone.modify_s(DN_CONFIG, mod) + + # get rid of default ACIs + mod = [(ldap.MOD_DELETE, 'aci', None)] + topology.standalone.modify_s(SUFFIX, mod) + + # Ok Now add the proper ACIs + ACI_TARGET = "(target = \"ldap:///%s\")" % SUBTREE_GREEN_1 + ACI_TARGETATTR = "(targetattr = \"objectclass || cn || sn || uid || givenname \")" + ACI_ALLOW = "(version 3.0; acl \"Allow search-read to green attrs\"; allow (read, search, compare)" + ACI_SUBJECT = " userdn = \"ldap:///all\";)" + ACI_BODY = ACI_TARGET + ACI_TARGETATTR + ACI_ALLOW + ACI_SUBJECT + mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)] + topology.standalone.modify_s(SUFFIX, mod) + + ACI_TARGET = "(target = \"ldap:///%s\")" % SUBTREE_GREEN_2 + ACI_TARGETATTR = "(targetattr != \"mail || employeenumber || mobile || telephonenumber \")" + ACI_BODY = ACI_TARGET + ACI_TARGETATTR + ACI_ALLOW + ACI_SUBJECT + mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)] + topology.standalone.modify_s(SUFFIX, mod) + + log.info("Adding %d test entries..." % USER_NUM) + for id in range(USER_NUM): + name = "%s.%d" % (TEST_USER, id) + mail = "%s@example.com" % name + for subtree in SUBTREES: + topology.standalone.add_s(Entry(("cn=%s,%s" % (name, subtree), { + 'objectclass': "top person organizationalPerson inetOrgPerson".split(), + 'sn': name, + 'cn': name, + 'uid': name, + 'givenname': 'test', + 'mail': mail, + 'description': 'description', + 'employeenumber': "%d" % id, + 'telephonenumber': "%d%d%d" % (id,id,id), + 'mobile': "%d%d%d" % (id,id,id), + 'l': 'MV', + 'title': 'Engineer'}))) + + +def gen_filtertests_basic(dm): + tests = [] + # 1. Simple filter - green attr - not/matching + tests.append(("(uid=xxxx)",0)) + tests.append(("(uid=user.1)",(3 if dm else 2))) + + # 2. Simple filter -red attr - not/matching + tests.append(("(mail=user.x@example.com)",0)) + tests.append(("(mail=user.1@example.com)",(3 if dm else 0))) + + # 3. NOT filter -green attr - not/matching + tests.append(("(!(objectclass=inetorgperson))",(4 if dm else 2))) + tests.append(("(!(objectclass=dummy))",(34 if dm else 22))) + + # 4. NOT filter - red attr - not/matching + tests.append(("(!(mail=user.1@example.com))",(31 if dm else 0))) + tests.append(("(!(mail=user.x@example.com))",(34 if dm else 0))) + + # 5. AND filter - green/green attr - not/matching + tests.append(("(&(objectclass=inetorgperson)(uid=user.1))",(3 if dm else 2))) + tests.append(("(&(objectclass=inetorgperson)(uid=user.x))",0)) + + # 6. AND filter - green/red attr - not/matching + tests.append(("(&(objectclass=inetorgperson)(mail=user.1@example.com))",(3 if dm else 0))) + tests.append(("(&(objectclass=inetorgperson)(mail=user.x@example.com))",0)) + + # 7. OR filter - green/green - not/matching/order + tests.append(("(|(uid=user.1)(sn=user.3))",(6 if dm else 4))) + tests.append(("(|(uid=user.x)(sn=user.3))",(3 if dm else 2))) + tests.append(("(|(uid=user.1)(sn=user.x))",(3 if dm else 2))) + + return tests + +def gen_filtertests_ext(dm): + ''' + the extended tests add OR components to the search filter using attributes + without access, either matching or not. + The returned entries have to be the same as without these OR parts + ''' + + tests = [] + + # 1. Simple filter - green attr - not/matching + tests.append(("(|(uid=xxxx)(mail=user.xxxx1@example.com))",0)) + tests.append(("(|(uid=xxxx)(mail=user.1@example.com))",(3 if dm else 0))) + tests.append(("(|(uid=user.1)(mail=user.xxxx1@example.com))",(3 if dm else 2))) + tests.append(("(|(uid=user.1)(mail=user.3@example.com))",(6 if dm else 2))) + + # 2. Simple filter - red attr - not/matching + tests.append(("(|(mail=user.x@example.com)(employeenumber=3))",(3 if dm else 0))) + tests.append(("(|(mail=user.x@example.com)(employeenumber=100))",0)) + tests.append(("(|(mail=user.1@example.com)(employeenumber=3))",(6 if dm else 0))) + tests.append(("(|(mail=user.1@example.com)(employeenumber=100))",(3 if dm else 0))) + + # 3. NOT filter - green attr - not/matching + tests.append(("(!(|(objectclass=inetorgperson)(employeenumber=3)))",(4 if dm else 2))) + tests.append(("(!(|(objectclass=inetorgperson)(employeenumber=100)))",(4 if dm else 2))) + tests.append(("(|(!(objectclass=inetorgperson))(employeenumber=3))",(7 if dm else 2))) + tests.append(("(|(!(objectclass=inetorgperson))(employeenumber=100))",(4 if dm else 2))) + + # 4. NOT filter - red attr - not/matching + tests.append(("(!(|(mail=user.1@example.com)(employeenumber=3)))",(28 if dm else 0))) + tests.append(("(!(|(mail=user.1@example.com)(employeenumber=100)))",(31 if dm else 0))) + tests.append(("(!(|(mail=user.x@example.com)(employeenumber=3)))",(31 if dm else 0))) + tests.append(("(!(|(mail=user.x@example.com)(employeenumber=100)))",(34 if dm else 0))) + + # 5. AND filter - green/green attr - not/matching + tests.append(("(|(&(objectclass=inetorgperson)(uid=user.1))(employeenumber=3))",(6 if dm else 2))) + tests.append(("(|(&(objectclass=inetorgperson)(uid=user.1))(employeenumber=100))",(3 if dm else 2))) + tests.append(("(&(objectclass=inetorgperson)(|(employeenumber=3)(uid=user.1)))",(6 if dm else 2))) + tests.append(("(&(objectclass=inetorgperson)(|(employeenumber=100)(uid=user.1)))",(3 if dm else 2))) + tests.append(("(&(|(employeenumber=3)(objectclass=inetorgperson))(uid=user.1))",(3 if dm else 2))) + tests.append(("(&(|(employeenumber=100)(objectclass=inetorgperson))(uid=user.1))",(3 if dm else 2))) + tests.append(("(|(&(objectclass=inetorgperson)(uid=user.x))(employeenumber=3))",(3 if dm else 0))) + tests.append(("(|(&(objectclass=inetorgperson)(uid=user.x))(employeenumber=100))", 0)) + tests.append(("(&(objectclass=inetorgperson)(|(employeenumber=3)(uid=user.x)))",(3 if dm else 0))) + tests.append(("(&(objectclass=inetorgperson)(|(employeenumber=100)(uid=user.x)))",0)) + tests.append(("(&(|(employeenumber=3)(objectclass=inetorgperson))(uid=user.x))",0)) + tests.append(("(&(|(employeenumber=100)(objectclass=inetorgperson))(uid=user.x))",0)) + + # 6. AND filter - green/red attr - not/matching + tests.append(("(&(|(employeenumber=3)(objectclass=inetorgperson))(mail=user.1@example.com))",(3 if dm else 0))) + tests.append(("(&(objectclass=inetorgperson)(|(employeenumber=3)(mail=user.1@example.com)))",(6 if dm else 0))) + tests.append(("(|(employeenumber=3)(&(objectclass=inetorgperson)(mail=user.1@example.com)))",(6 if dm else 0))) + tests.append(("(&(|(employeenumber=100)(objectclass=inetorgperson))(mail=user.1@example.com))",(3 if dm else 0))) + tests.append(("(&(objectclass=inetorgperson)(|(employeenumber=100)(mail=user.1@example.com)))",(3 if dm else 0))) + tests.append(("(|(employeenumber=100)(&(objectclass=inetorgperson)(mail=user.1@example.com)))",(3 if dm else 0))) + tests.append(("(&(objectclass=inetorgperson)(mail=user.x@example.com))",0)) + + # 7. OR filter - green/green - not/matching/order + tests.append(("(|(uid=user.1)(employeenumber=3)(sn=user.3))",(6 if dm else 4))) + tests.append(("(|(uid=user.1)(sn=user.3)(employeenumber=3))",(6 if dm else 4))) + tests.append(("(|(uid=user.x)(employeenumber=3)(sn=user.3))",(3 if dm else 2))) + tests.append(("(|(uid=user.x)(sn=user.3)(employeenumber=3))",(3 if dm else 2))) + tests.append(("(|(uid=user.1)(employeenumber=3)(sn=user.x))",(6 if dm else 2))) + tests.append(("(|(uid=user.1)(sn=user.x)(employeenumber=3))",(6 if dm else 2))) + tests.append(("(|(uid=user.1)(unknown=3)(sn=user.3))",(6 if dm else 4))) + tests.append(("(|(uid=user.1)(sn=user.3)(unknown=3))",(6 if dm else 4))) + tests.append(("(|(uid=user.x)(unknown=3)(sn=user.3))",(3 if dm else 2))) + tests.append(("(|(uid=user.x)(sn=user.3)(unknown=3))",(3 if dm else 2))) + tests.append(("(|(uid=user.1)(unknown=3)(sn=user.x))",(3 if dm else 2))) + tests.append(("(|(uid=user.1)(sn=user.x)(unknown=3))",(3 if dm else 2))) + + return tests + +def run_ticket48275_search(topology, dm, basic): + + if basic: + tests = gen_filtertests_basic(dm) + else: + tests = gen_filtertests_ext(dm) + + topology.standalone.log.info("\n\n######################### SEARCH ######################\n") + + cnt = 0 + passed = 0 + for (fstr, exp) in tests: + cnt += 1 + ents = topology.standalone.search_s(SUBTREE_BASE, ldap.SCOPE_SUBTREE, fstr) + rec = len(ents) + topology.standalone.log.info("Test %d: filter \"%s\", expected: %d, received: %d\n" % (cnt, fstr, exp, rec)) + if exp == rec: + passed += 1 + + assert(cnt==passed) + +def test_ticket48275_search_basic_dm(topology): + + topology.standalone.simple_bind_s(DN_DM, PASSWORD) + run_ticket48275_search(topology, dm=True, basic=True) + +def test_ticket48275_search_basic_user(topology): + + topology.standalone.simple_bind_s(BIND_DN, BIND_PW) + run_ticket48275_search(topology, dm=False, basic=True) + +def test_ticket48275_search_ext_dm(topology): + + topology.standalone.simple_bind_s(DN_DM, PASSWORD) + run_ticket48275_search(topology, dm=True, basic=False) + +def test_ticket48275_search_ext_user(topology): + + topology.standalone.simple_bind_s(BIND_DN, BIND_PW) + run_ticket48275_search(topology, dm=False, basic=False) + + +def test_ticket48275_final(topology): + topology.standalone.delete() + log.info('Testcase PASSED') + + +def run_isolated(): + ''' + run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..) + To run isolated without py.test, you need to + - edit this file and comment '@pytest.fixture' line before 'topology' function. + - set the installation prefix + - run this program + ''' + global installation_prefix + installation_prefix = None + + topo = topology(True) + test_ticket48275_init(topo) + + test_ticket48275_search_dm(topo) + + test_ticket48275_final(topo) + + +if __name__ == '__main__': + run_isolated() + -- 2.4.3