#49492 Issue #35 - dsconf automember support
Closed 3 years ago by spichugi. Opened 6 years ago by alisha17.
alisha17/389-ds-base automember  into  master

@@ -0,0 +1,139 @@ 

+ import logging

+ import pytest

+ import os

+ import ldap

+ from lib389.utils import ds_is_older

+ from lib389._constants import *

+ from lib389.plugins import AutoMembershipPlugin, AutoMembershipDefinition, AutoMembershipDefinitions

+ from lib389._mapped_object import DSLdapObjects, DSLdapObject

+ from lib389 import agreement

+ from lib389.idm.user import UserAccount, UserAccounts, TEST_USER_PROPERTIES

+ from lib389.idm.group import Groups, Group

+ from lib389.topologies import topology_st as topo

+ from lib389._constants import DEFAULT_SUFFIX

+ 

+ 

+ # Skip on older versions

+ pytestmark = pytest.mark.skipif(ds_is_older('1.3.7'), reason="Not implemented")

+ 

+ DEBUGGING = os.getenv("DEBUGGING", default=False)

+ if DEBUGGING:

+     logging.getLogger(__name__).setLevel(logging.DEBUG)

+ else:

+     logging.getLogger(__name__).setLevel(logging.INFO)

+ log = logging.getLogger(__name__)

+ 

+ 

+ @pytest.fixture(scope="module")

+ def automember_fixture(topo, request):

+ 

+     groups = Groups(topo.standalone, DEFAULT_SUFFIX)

+     group = groups.create(properties={'cn': 'testgroup'})

+ 

+     automemberplugin = AutoMembershipPlugin(topo.standalone)

+     automemberplugin.enable()

+ 

+     topo.standalone.restart() 

+ 

+     automember_prop = {

+         'cn': 'testgroup_definition',

+         'autoMemberScope': 'ou=People,' + DEFAULT_SUFFIX,

+         'autoMemberFilter': 'objectclass=*',

+         'autoMemberDefaultGroup': group.dn,

+         'autoMemberGroupingAttr': 'member:dn',

+     }

+ 

+     automembers = AutoMembershipDefinitions(topo.standalone, "cn=Auto Membership Plugin,cn=plugins,cn=config")

+ 

+     automember = automembers.create(properties=automember_prop)

+ 

+     return (group, automembers, automember)

+ 

+ 

+ def test_automemberscope(automember_fixture, topo):

+     """Test if the automember scope is valid

+ 

+     :id: c3d3f250-e7fd-4441-8387-3d24c156e982

+     :setup: Standalone instance, enabled Auto Membership Plugin

+     :steps:

+         1. Create automember with invalid cn that raises 

+            UNWILLING_TO_PERFORM exception

+         2. If exception raised, set scope to any cn

+         3. If exception is not raised, set scope to with ou=People

+     :expectedresults:

+         1. Should be success

+         2. Should be success

+         3. Should be success

+     """

+ 

+     (group, automembers, automember) = automember_fixture

+ 

+     automember_prop = {

+         'cn': 'anyrandomcn',

+         'autoMemberScope': 'ou=People,' + DEFAULT_SUFFIX,

+         'autoMemberFilter': 'objectclass=*',

+         'autoMemberDefaultGroup': group.dn,

+         'autoMemberGroupingAttr': 'member:dn',

+     }

+ 

+     # depends on issue #49465

+     

+     # with pytest.raises(ldap.UNWILLING_TO_PERFORM):

+     #     automember = automembers.create(properties=automember_prop)

+     # automember.set_scope("cn=No Entry,%s" % DEFAULT_SUFFIX)

+ 

+     automember.set_scope("ou=People,%s" % DEFAULT_SUFFIX)	

+ 

+ 

+ def test_automemberfilter(automember_fixture, topo):

+     """Test if the automember filter is valid

+ 

+     :id: 935c55de-52dc-4f80-b7dd-3aacd30f6df2

+     :setup: Standalone instance, enabled Auto Membership Plugin

+     :steps:

+         1. Create automember with invalid filter that raises 

+            UNWILLING_TO_PERFORM exception

+         2. If exception raised, set filter to the invalid filter

+         3. If exception is not raised, set filter as all objectClasses

+     :expectedresults:

+         1. Should be success

+         2. Should be success

+         3. Should be success

+     """

+ 

+     (group, automembers, automember) = automember_fixture

+ 

+     automember_prop = {

+         'cn': 'anyrandomcn',

+         'autoMemberScope': 'ou=People,' + DEFAULT_SUFFIX,

+         'autoMemberFilter': '(ou=People',

+         'autoMemberDefaultGroup': group.dn,

+         'autoMemberGroupingAttr': 'member:dn',

+     }

+ 

+     with pytest.raises(ldap.UNWILLING_TO_PERFORM):

+         automember = automembers.create(properties=automember_prop)

+         automember.set_filter("(ou=People")

+ 

+     automember.set_filter("objectClass=*")

+ 

+ 

+ def test_adduser(automember_fixture, topo):

+     """Test if member is automatically added to the group

+ 

+     :id: 14f1e2f5-2162-41ab-962c-5293516baf2e

+     :setup: Standalone instance, enabled Auto Membership Plugin

+     :steps:

+         1. Create a user

+         2. Assert that the user is member of the group

+     :expectedresults:

+         1. Should be success

+         2. Should be success

+     """    

+ 

+     (group, automembers, automember) = automember_fixture

+ 

+     users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)

+     user = users.create(properties=TEST_USER_PROPERTIES)

+ 

+     assert group.is_member(user.dn)

@@ -222,10 +222,10 @@ 

          self._log.debug("%s present(%r) %s" % (self._dn, attr, value))

  

          e = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, attrlist=[attr, ], serverctrls=self._server_controls, clientctrls=self._client_controls)[0]

-         if value is None:

-             return e.hasAttr(attr)

-         else:

-             return e.hasValue(attr, value)

+         values = self.get_attr_vals_bytes(attr)

+         self._log.debug("%s contains %s" % (self._dn, values))

+ 

+         return ensure_bytes(value).lower() in [x.lower() for x in values]

  

      def add(self, key, value):

          """Add an attribute with a value

@@ -387,9 +387,114 @@ 

          super(AccountUsabilityPlugin, self).__init__(instance, dn)

  

  class AutoMembershipPlugin(Plugin):

+     _plugin_properties = {

+         'cn' : 'Auto Membership Plugin',

+         'nsslapd-pluginEnabled' : 'off',

+         'nsslapd-pluginPath' : 'libautomember-plugin',

+         'nsslapd-pluginInitfunc' : 'automember_init',

+         'nsslapd-pluginType' : 'betxnpreoperation',

+         'nsslapd-plugin-depends-on-type' : 'database',

+         'nsslapd-pluginId' : 'Auto Membership',

+         'nsslapd-pluginVendor' : '389 Project',

+         'nsslapd-pluginVersion' : '1.3.7.0',

+         'nsslapd-pluginDescription' : 'Auto Membership plugin',

+     }

+ 

      def __init__(self, instance, dn="cn=Auto Membership Plugin,cn=plugins,cn=config"):

          super(AutoMembershipPlugin, self).__init__(instance, dn)

  

+ class AutoMembershipDefinition(DSLdapObject):

+     """A single instance of Auto Membership Plugin entry

+ 

+         :param instance: An instance

+         :type instance: lib389.DirSrv

+         :param dn: Entry DN

+         :type dn: str

+     """

+ 

+     def __init__(self, instance, dn=None):

+         super(AutoMembershipDefinition, self).__init__(instance, dn)

+         self._rdn_attribute = 'cn'

+         self._must_attributes = ['cn']

+         self._create_objectclasses = ['top', 'AutoMemberDefinition']

+         self._protected = False

+ 

+     def get_groupattr(self):

+         """Get grouping attributes

+ 

+             :returns: autoMemberGroupingAttr values

+         """

+         return self.get_attr_vals_utf8('autoMemberGroupingAttr')

+ 

+     def set_groupattr(self, attr):

+         """Set grouping attributes

+ 

+             :param attr: autoMemberGroupingAttr value

+             :type attr: str

+         """

+         self.set('autoMemberGroupingAttr', attr)

+ 

+     def get_defaultgroup(self, attr):

+         """Get default group

+ 

+             :returns: autoMemberDefaultGroup value

+         """

+         return self.get_attr_vals_utf8('autoMemberDefaultGroup')

+ 

+     def set_defaultgroup(self, attr):

+         """Set default group

+ 

+             :param attr: autoMemberDefaultGroup value

+             :type attr: str

+         """

+         self.set('autoMemberDefaultGroup', attr)  

+ 

+     def get_scope(self, attr):

+         """Get scope

+ 

+             :returns: autoMemberScope value

+         """        

+         return self.get_attr_vals_utf8('autoMemberScope')

+ 

+     def set_scope(self, attr):

+         """Set scope

+ 

+             :param attr: autoMemberScope value

+             :type attr: str

+         """        

+         self.set('autoMemberScope', attr)

+ 

+     def get_filter(self, attr):

+         """Get filter

+ 

+             :returns: autoMemberFilter value

+         """       

+         return self.get_attr_vals_utf8('autoMemberFilter')

+ 

+     def set_filter(self, attr):

+         """Set filter

+ 

+             :param attr: autoMemberFilter value

+             :type attr: str

+         """ 

+         self.set('autoMemberFilter', attr)

+ 

+ class AutoMembershipDefinitions(DSLdapObjects):

+     """DSLdapObjects that represents Auto Membership Plugin entry

+ 

+         :param instance: An instance

+         :type instance: lib389.DirSrv

+         :param basedn: Base DN for all account entries below

+         :type basedn: str

+     """

+ 

+     def __init__(self, instance, basedn):

+         super(AutoMembershipDefinitions, self).__init__(instance)

+         self._objectclasses = ['top','autoMemberDefinition']

+         self._filterattrs = ['cn']

+         self._childobject = AutoMembershipDefinition

+         self._basedn = basedn

+ 

  class ContentSynchronizationPlugin(Plugin):

      def __init__(self, instance, dn="cn=Content Synchronization,cn=plugins,cn=config"):

          super(ContentSynchronizationPlugin, self).__init__(instance, dn)

Bug Description: Add support for managing automember to dsconf

Fix Description: Initial patch which adds AutoMembershipPlugin, AutoMembershipDefinition
and AutoMembershipDefinitions classes to plugins.py and adds tests for checking valid scope,
valid filter and if user is correctly added to the group.

https://pagure.io/lib389/issue/35

Author: Alisha Aneja

Review by: ???

I'm happy with this, code looks good,

@spichugi can you check this also for me.? I think you'll say something about the docstrings ...

It's better to have two lines between test functions. It increases readability

We need to have proper docstrings for every test case.
You can find the guideline for it here: https://fedorapeople.org/~spichugi/html/guidelines.html

 """Test if member is automatically added to the group

:id: 38621a51-03bc-4fba-93ef-7e525df87c5d
:setup: Standalone instance, enabled Auto Membership Plugin
:steps:
     1. Create a user
     2. Assert that the user is member of the group
:expectedresults:
     1. Should be success
     2. Should be success
 """

You can generate :id: with:

python -c 'import uuid; print(uuid.uuid4())'

I think, it's better to get right value in the beginning. Please, use get_attr_vals_bytes

We need to have all new objects documented. Better in the beginning :)
For init part, you can add the following docstring:

"""A single instance of Auto Membership Plugin entry

:param instance: An instance
:type instance: lib389.DirSrv
:param dn: Entry DN
:type dn: str
"""

Here it can be something like this:

   """Get grouping attributes

    :returns: autoMemberGroupingAttr values
    """

For the Python 3 sake, we better get the values while specifying type explicitly. Like get_attr_vals_utf8

"""DSLdapObjects that represents Auto Membership Plugin entry

:param instance: An instance
:type instance: lib389.DirSrv
:param basedn: Base DN for all account entries below
:type basedn: str
"""

Done. Please, check it and correct me if I've missed some points :)

rebased onto 69a015c5a0a0bfd8169ec1cf88510ff7dfa2edf9

6 years ago

1 new commit added

  • Issue #35 - dsconf automember support
6 years ago

Great! I think this is much better. Just need to fix set_scope I think and rebase to master, then we can merge :)

rebased onto cf25c958ec123cf71f78aca51e0a9a1fbd2f8331

6 years ago

rebased onto bcc13d3da64a5cd90b401844b6e2e134ec77624a

6 years ago

rebased onto debe278

6 years ago

Pull-Request has been merged by firstyear

6 years ago

389-ds-base is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in 389-ds-base's github repository.

This pull request has been cloned to Github as issue and is available here:
- https://github.com/389ds/389-ds-base/issues/2551

If you want to continue to work on the PR, please navigate to the github issue,
download the patch from the attachments and file a new pull request.

Thank you for understanding. We apologize for all inconvenience.

Pull-Request has been closed by spichugi

3 years ago