From 9724e8bb1df9fa27c42911c061da63e4245cc8f6 Mon Sep 17 00:00:00 2001 From: Anuj Borah Date: Apr 17 2019 09:47:28 +0000 Subject: Issue: 50313 - Add a NestedRole type to lib389 Add the NestedRole and the NestedRoles classes to src/lib389/lib389/idm/role.py Add one test case that will test that the new class NestedRoles is working fine. https://pagure.io/389-ds-base/issue/50313 Reviewed by: Simon Pichugin, thierry bordaz --- diff --git a/dirsrvtests/tests/suites/roles/basic_test.py b/dirsrvtests/tests/suites/roles/basic_test.py index 1d3079a..0b281bb 100644 --- a/dirsrvtests/tests/suites/roles/basic_test.py +++ b/dirsrvtests/tests/suites/roles/basic_test.py @@ -6,13 +6,20 @@ # See LICENSE for details. # --- END COPYRIGHT BLOCK --- -import pytest, os + +""" +Importing necessary Modules. +""" + +import os +import pytest + from lib389._constants import PW_DM, DEFAULT_SUFFIX from lib389.idm.user import UserAccount, UserAccounts from lib389.idm.organization import Organization from lib389.idm.organizationalunit import OrganizationalUnit from lib389.topologies import topology_st as topo -from lib389.idm.role import FilterRoles, ManagedRole, ManagedRoles +from lib389.idm.role import FilterRoles, ManagedRoles, NestedRoles from lib389.idm.domain import Domain @@ -45,11 +52,11 @@ def test_filterrole(topo): 'ou': 'eng', } - ou = OrganizationalUnit(topo.standalone, "ou=eng,o=acivattr,{}".format(DEFAULT_SUFFIX)) - ou.create(properties=properties) + ou_ou = OrganizationalUnit(topo.standalone, "ou=eng,o=acivattr,{}".format(DEFAULT_SUFFIX)) + ou_ou.create(properties=properties) properties = {'ou': 'sales'} - ou = OrganizationalUnit(topo.standalone, "ou=sales,o=acivattr,{}".format(DEFAULT_SUFFIX)) - ou.create(properties=properties) + ou_ou = OrganizationalUnit(topo.standalone, "ou=sales,o=acivattr,{}".format(DEFAULT_SUFFIX)) + ou_ou.create(properties=properties) roles = FilterRoles(topo.standalone, DNBASE) roles.create(properties={'cn': 'FILTERROLEENGROLE', 'nsRoleFilter': 'cn=eng*'}) @@ -64,7 +71,8 @@ def test_filterrole(topo): 'homeDirectory': '/home/' + 'salesuser1', 'userPassword': PW_DM } - user = UserAccount(topo.standalone, 'cn=salesuser1,ou=sales,o=acivattr,{}'.format(DEFAULT_SUFFIX)) + user = UserAccount(topo.standalone, + 'cn=salesuser1,ou=sales,o=acivattr,{}'.format(DEFAULT_SUFFIX)) user.create(properties=properties) properties = { @@ -76,7 +84,8 @@ def test_filterrole(topo): 'homeDirectory': '/home/' + 'salesmanager1', 'userPassword': PW_DM, } - user = UserAccount(topo.standalone, 'cn=salesmanager1,ou=sales,o=acivattr,{}'.format(DEFAULT_SUFFIX)) + user = UserAccount(topo.standalone, + 'cn=salesmanager1,ou=sales,o=acivattr,{}'.format(DEFAULT_SUFFIX)) user.create(properties=properties) properties = { @@ -88,7 +97,8 @@ def test_filterrole(topo): 'homeDirectory': '/home/' + 'enguser1', 'userPassword': PW_DM } - user = UserAccount(topo.standalone,'cn=enguser1,ou=eng,o=acivattr,{}'.format(DEFAULT_SUFFIX)) + user = UserAccount(topo.standalone, + 'cn=enguser1,ou=eng,o=acivattr,{}'.format(DEFAULT_SUFFIX)) user.create(properties=properties) properties = { @@ -100,24 +110,29 @@ def test_filterrole(topo): 'homeDirectory': '/home/' + 'engmanager1', 'userPassword': PW_DM } - user = UserAccount(topo.standalone, 'cn=engmanager1,ou=eng,o=acivattr,{}'.format(DEFAULT_SUFFIX)) + user = UserAccount(topo.standalone, + 'cn=engmanager1,ou=eng,o=acivattr,{}'.format(DEFAULT_SUFFIX)) user.create(properties=properties) - #user with cn=sales* will automatically memeber of nsfilterrole cn=filterrolesalesrole,o=acivattr,dc=example,dc=com - assert UserAccount(topo.standalone, 'cn=salesuser1,ou=sales,o=acivattr,dc=example,dc=com').get_attr_val_utf8( - 'nsrole') == 'cn=filterrolesalesrole,o=acivattr,dc=example,dc=com' + # user with cn=sales* will automatically memeber of nsfilterrole + # cn=filterrolesalesrole,o=acivattr,dc=example,dc=com + assert UserAccount(topo.standalone, + 'cn=salesuser1,ou=sales,o=acivattr,dc=example,dc=com').\ + get_attr_val_utf8('nsrole') == 'cn=filterrolesalesrole,o=acivattr,dc=example,dc=com' # same goes to SALES_MANAGER assert UserAccount(topo.standalone, SALES_MANAGER).get_attr_val_utf8( 'nsrole') == 'cn=filterrolesalesrole,o=acivattr,dc=example,dc=com' - # user with cn=eng* will automatically memeber of nsfilterrole cn=filterroleengrole,o=acivattr,dc=example,dc=com - assert UserAccount(topo.standalone, 'cn=enguser1,ou=eng,o=acivattr,dc=example,dc=com').get_attr_val_utf8( - 'nsrole') == 'cn=filterroleengrole,o=acivattr,dc=example,dc=com' + # user with cn=eng* will automatically memeber of nsfilterrole + # cn=filterroleengrole,o=acivattr,dc=example,dc=com + assert UserAccount(topo.standalone, 'cn=enguser1,ou=eng,o=acivattr,dc=example,dc=com').\ + get_attr_val_utf8('nsrole') == 'cn=filterroleengrole,o=acivattr,dc=example,dc=com' # same goes to ENG_MANAGER assert UserAccount(topo.standalone, ENG_MANAGER).get_attr_val_utf8( 'nsrole') == 'cn=filterroleengrole,o=acivattr,dc=example,dc=com' - for DN in [ENG_USER, SALES_UESER, ENG_MANAGER, SALES_MANAGER, FILTERROLESALESROLE, FILTERROLEENGROLE, ENG_OU, - SALES_OU, DNBASE]: - UserAccount(topo.standalone, DN).delete() + for dn_dn in [ENG_USER, SALES_UESER, ENG_MANAGER, SALES_MANAGER, + FILTERROLESALESROLE, FILTERROLEENGROLE, ENG_OU, + SALES_OU, DNBASE]: + UserAccount(topo.standalone, dn_dn).delete() def test_managedrole(topo): @@ -140,14 +155,14 @@ def test_managedrole(topo): # Create user and Assign the role to the entry uas = UserAccounts(topo.standalone, DEFAULT_SUFFIX, rdn=None) uas.create(properties={ - 'uid': 'Fail', - 'cn': 'Fail', - 'sn': 'user', - 'uidNumber': '1000', - 'gidNumber': '2000', - 'homeDirectory': '/home/' + 'Fail', - 'nsRoleDN': role.dn, - 'userPassword': PW_DM + 'uid': 'Fail', + 'cn': 'Fail', + 'sn': 'user', + 'uidNumber': '1000', + 'gidNumber': '2000', + 'homeDirectory': '/home/' + 'Fail', + 'nsRoleDN': role.dn, + 'userPassword': PW_DM }) # Create user and do not Assign any role to the entry @@ -163,20 +178,23 @@ def test_managedrole(topo): }) # Assert that Manage role entry is created and its searchable - assert ManagedRoles(topo.standalone, DEFAULT_SUFFIX).list()[0].dn == 'cn=ROLE1,dc=example,dc=com' + assert ManagedRoles(topo.standalone, DEFAULT_SUFFIX).list()[0].dn \ + == 'cn=ROLE1,dc=example,dc=com' # Set an aci that will deny ROLE1 manage role - Domain(topo.standalone, DEFAULT_SUFFIX).add('aci', '(targetattr=*)(version 3.0; aci "role aci"; deny(all) roledn="ldap:///{}";)'.format(role.dn),) + Domain(topo.standalone, DEFAULT_SUFFIX).\ + add('aci', '(targetattr=*)(version 3.0; aci "role aci";' + ' deny(all) roledn="ldap:///{}";)'.format(role.dn),) # Crate a connection with cn=Fail which is member of ROLE1 conn = UserAccount(topo.standalone, "uid=Fail,{}".format(DEFAULT_SUFFIX)).bind(PW_DM) # Access denied to ROLE1 members - assert 0 == len(ManagedRoles(conn, DEFAULT_SUFFIX).list()) + assert not ManagedRoles(conn, DEFAULT_SUFFIX).list() # Now create a connection with cn=Success which is not a member of ROLE1 conn = UserAccount(topo.standalone, "uid=Success,{}".format(DEFAULT_SUFFIX)).bind(PW_DM) # Access allowed here - assert 1 == len(ManagedRoles(conn, DEFAULT_SUFFIX).list()) + assert ManagedRoles(conn, DEFAULT_SUFFIX).list() for i in uas.list(): i.delete() @@ -185,6 +203,92 @@ def test_managedrole(topo): i.delete() +@pytest.fixture(scope="function") +def _final(request, topo): + """ + Removes and Restores ACIs after the test. + """ + aci_list = Domain(topo.standalone, DEFAULT_SUFFIX).get_attr_vals('aci') + + def finofaci(): + """ + Removes and Restores ACIs and other users after the test. + """ + domain = Domain(topo.standalone, DEFAULT_SUFFIX) + domain.remove_all('aci') + + managed_roles = ManagedRoles(topo.standalone, DEFAULT_SUFFIX) + nested_roles = NestedRoles(topo.standalone, DEFAULT_SUFFIX) + users = UserAccounts(topo.standalone, DEFAULT_SUFFIX) + + for i in managed_roles.list() + nested_roles.list() + users.list(): + i.delete() + + for i in aci_list: + domain.add("aci", i) + + request.addfinalizer(finofaci) + + +def test_nestedrole(topo, _final): + """ + :id: d52a9cw0-3bg6-11e9-9b7b-8c16451d917t + :setup: Standalone server + :steps: + 1. Add test entry + 2. Add ACI + 3. Search managed role entries + :expectedresults: + 1. Entry should be added + 2. Operation should succeed + 3. Operation should succeed + """ + # Create Managed role entry + managed_roles = ManagedRoles(topo.standalone, DEFAULT_SUFFIX) + managed_role1 = managed_roles.create(properties={"cn": 'managed_role1'}) + managed_role2 = managed_roles.create(properties={"cn": 'managed_role2'}) + + # Create nested role entry + nested_roles = NestedRoles(topo.standalone, DEFAULT_SUFFIX) + nested_role = nested_roles.create(properties={"cn": 'nested_role', + "nsRoleDN": [managed_role1.dn, managed_role2.dn]}) + + # Create user and assign managed role to it + users = UserAccounts(topo.standalone, DEFAULT_SUFFIX) + user1 = users.create_test_user(uid=1, gid=1) + user1.set('nsRoleDN', managed_role1.dn) + user1.set('userPassword', PW_DM) + + # Create another user and assign managed role to it + user2 = users.create_test_user(uid=2, gid=2) + user2.set('nsRoleDN', managed_role2.dn) + user2.set('userPassword', PW_DM) + + # Create another user and do not assign any role to it + user3 = users.create_test_user(uid=3, gid=3) + user3.set('userPassword', PW_DM) + + # Create a ACI with deny access to nested role entry + Domain(topo.standalone, DEFAULT_SUFFIX).\ + add('aci', f'(targetattr=*)(version 3.0; aci ' + f'"role aci"; deny(all) roledn="ldap:///{nested_role.dn}";)') + + # Create connection with 'uid=test_user_1,ou=People,dc=example,dc=com' member of managed_role1 + # and search while bound as the user + conn = users.get('test_user_1').bind(PW_DM) + assert not UserAccounts(conn, DEFAULT_SUFFIX).list() + + # Create connection with 'uid=test_user_2,ou=People,dc=example,dc=com' member of managed_role2 + # and search while bound as the user + conn = users.get('test_user_2').bind(PW_DM) + assert not UserAccounts(conn, DEFAULT_SUFFIX).list() + + # Create connection with 'uid=test_user_3,ou=People,dc=example,dc=com' and + # search while bound as the user + conn = users.get('test_user_3').bind(PW_DM) + assert UserAccounts(conn, DEFAULT_SUFFIX).list() + + if __name__ == "__main__": CURRENT_FILE = os.path.realpath(__file__) pytest.main("-s -v %s" % CURRENT_FILE) diff --git a/src/lib389/lib389/idm/role.py b/src/lib389/lib389/idm/role.py index 91699d4..b630bff 100644 --- a/src/lib389/lib389/idm/role.py +++ b/src/lib389/lib389/idm/role.py @@ -112,4 +112,52 @@ class ManagedRoles(DSLdapObjects): ] self._filterattrs = ['cn'] self._basedn = basedn - self._childobject = ManagedRole \ No newline at end of file + self._childobject = ManagedRole + + +class NestedRole(DSLdapObject): + """A single instance of NestedRole entry to create NestedRole role. + + :param instance: An instance + :type instance: lib389.DirSrv + :param dn: Entry DN + :type dn: str + + """ + def __init__(self, instance, dn=None): + super(NestedRole, self).__init__(instance, dn) + self._must_attributes = ['cn', 'nsRoleDN'] + self._rdn_attribute = 'cn' + self._create_objectclasses = [ + 'top', + 'nsRoleDefinition', + 'nsComplexRoleDefinition', + 'ldapSubEntry', + 'nsNestedRoleDefinition' + ] + + +class NestedRoles(DSLdapObjects): + """DSLdapObjects that represents all NestedRoles entries in suffix. + + This instance is used mainly for search operation NestedRoles role + + :param instance: An instance + :type instance: lib389.DirSrv + :param basedn: Suffix DN + :type basedn: str + :param rdn: The DN that will be combined wit basedn + :type rdn: str + """ + def __init__(self, instance, basedn): + super(NestedRoles, self).__init__(instance) + self._objectclasses = [ + 'top', + 'nsRoleDefinition', + 'nsComplexRoleDefinition', + 'ldapSubEntry', + 'nsNestedRoleDefinition' + ] + self._filterattrs = ['cn'] + self._basedn = basedn + self._childobject = NestedRole