Hello,
This adds "managed" permissions, the framework that will make our default permissions merge IPA updates and user changes sanely.

There is no updater yet, nor does this add any actual managed permissions, so there's no user-visible change (beyond help text and a disabled option). To test the patch you might need to touch LDAP directly.

Ticket: https://fedorahosted.org/freeipa/ticket/4033
Design (no updater & plugin changes yet): http://www.freeipa.org/page/V3/Managed_Read_permissions

0447 - Minor fixes.
0448 - Since you can't create managed permissions through the API, I needed to get creative with the declarative tests. The tests will need a custom function that adds a managed perm.
0449 - The change itself.


FYI, my roadmap:
I'll now concentrate on #4074 (Use targetfilter & targetattrfilter in permissions) since it looks like we'll want most of the default permissions to use location + objectclass targetfilter. (The ticket turned out to be trickier than it seems, stay tuned).
http://www.redhat.com/archives/freeipa-devel/2013-December/msg00063.html

I'm planning to add the updater, and design how plugins will advertise their default permissions, after we decide how most of the default permissions will look.

--
PetrĀ³
From 3c7a9f5147e7ea9d0eae0c1a416c74435c63702e Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pvikt...@redhat.com>
Date: Fri, 3 Jan 2014 12:01:42 +0100
Subject: [PATCH] Permission plugin fixes

- Fix i18n for plugin docstring
- Fix error when the aci attribute is not present on an entry
- Fix error when raising exception for ACI not found
---
 ipalib/plugins/permission.py | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/ipalib/plugins/permission.py b/ipalib/plugins/permission.py
index 204574697beac40917f3671787146f421d84c93b..eb720131fa9b5686f17a01bf9d73da02a4675608 100644
--- a/ipalib/plugins/permission.py
+++ b/ipalib/plugins/permission.py
@@ -32,27 +32,27 @@
 
 __doc__ = _("""
 Permissions
-""" + """
+""") + _("""
 A permission enables fine-grained delegation of rights. A permission is
 a human-readable wrapper around a 389-ds Access Control Rule,
 or instruction (ACI).
 A permission grants the right to perform a specific task such as adding a
 user, modifying a group, etc.
-""" + """
+""") + _("""
 A permission may not contain other permissions.
-""" + """
+""") + _("""
 * A permission grants access to read, write, add, delete, read, search,
   or compare.
 * A privilege combines similar permissions (for example all the permissions
   needed to add a user).
 * A role grants a set of privileges to users, groups, hosts or hostgroups.
-""" + """
+""") + _("""
 A permission is made up of a number of different parts:
 
 1. The name of the permission.
 2. The target of the permission.
 3. The rights granted by the permission.
-""" + """
+""") + _("""
 Rights define what operations are allowed, and may be one or more
 of the following:
 1. write - write one or more attributes
@@ -62,28 +62,28 @@
 5. add - add a new entry to the tree
 6. delete - delete an existing entry
 7. all - all permissions are granted
-""" + """
+""") + _("""
 Note the distinction between attributes and entries. The permissions are
 independent, so being able to add a user does not mean that the user will
 be editable.
-""" + """
+""") + _("""
 There are a number of allowed targets:
 1. subtree: a DN; the permission applies to the subtree under this DN
 2. target filter: an LDAP filter
 3. target: DN with possible wildcards, specifies entries permission applies to
-""" + """
+""") + _("""
 Additionally, there are the following convenience options.
 Setting one of these options will set the corresponding attribute(s).
 1. type: a type of object (user, group, etc); sets subtree and target filter.
 2. memberof: apply to members of a group; sets target filter
 3. targetgroup: grant access to modify a specific group (such as granting
    the rights to manage group membership); sets target.
-""" + """
+""") + _("""
 EXAMPLES:
-""" + """
+""") + _("""
  Add a permission that grants the creation of users:
    ipa permission-add --type=user --permissions=add "Add Users"
-""" + """
+""") + _("""
  Add a permission that grants the ability to manage group membership:
    ipa permission-add --attrs=member --permissions=write --type=group "Manage Group Members"
 """)
@@ -421,7 +421,7 @@ def _replace_aci(self, permission_entry, old_name=None, new_acistring=None):
             acientry['aci'].remove(acistring)
         if new_acistring:
             self.log.debug('Adding ACI %r to %s' % (new_acistring, acidn))
-            acientry['aci'].append(new_acistring)
+            acientry.setdefault('aci', []).append(new_acistring)
         try:
             ldap.update_entry(acientry)
         except errors.EmptyModlist:
@@ -742,7 +742,8 @@ def pre_callback(self, ldap, dn, *keys, **options):
         try:
             self.obj.remove_aci(entry)
         except errors.NotFound:
-            errors.NotFound('ACI of permission %s was not found' % keys[0])
+            errors.NotFound(
+                reason=_('ACI of permission %s was not found') % keys[0])
 
         return dn
 
-- 
1.8.4.2

From 4f764e07942bdaa62b68c09ecd455b5b255b1ae0 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pvikt...@redhat.com>
Date: Fri, 13 Sep 2013 16:08:22 +0200
Subject: [PATCH] Make it possible to call custom functions in Declarative
 tests

Sometimes, we will want to do more than just call IPA commands and
check the output. This patch makes it possible to add arbitrary
functions to Declarative tests. They will be called as part of
the sequence of tests.
---
 ipatests/test_xmlrpc/xmlrpc_test.py | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/ipatests/test_xmlrpc/xmlrpc_test.py b/ipatests/test_xmlrpc/xmlrpc_test.py
index ec3007a2b859de6e01fd3b3f5bbe18778884ec8a..02c458d08d3f10e2de2cc908e5e6fabb81f52e79 100644
--- a/ipatests/test_xmlrpc/xmlrpc_test.py
+++ b/ipatests/test_xmlrpc/xmlrpc_test.py
@@ -304,11 +304,18 @@ def test_generator(self):
         # Iterate through the tests:
         name = self.__class__.__name__
         for (i, test) in enumerate(self.tests):
-            nice = '%s[%d]: %s: %s' % (
-                name, i, test['command'][0], test.get('desc', '')
-            )
-            func = lambda: self.check(nice, **test)
-            func.description = nice
+            if callable(test):
+                func = lambda: test(self)
+                nice = '%s[%d]: call %s: %s' % (
+                    name, i, test.__name__, test.__doc__
+                )
+                func.description = nice
+            else:
+                nice = '%s[%d]: %s: %s' % (
+                    name, i, test['command'][0], test.get('desc', '')
+                )
+                func = lambda: self.check(nice, **test)
+                func.description = nice
             yield (func,)
 
         # Iterate through post-cleanup:
-- 
1.8.4.2

From b48bd11d2dfc90e4567fd9c4c475df66bc95a5d7 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pvikt...@redhat.com>
Date: Fri, 13 Sep 2013 16:08:22 +0200
Subject: [PATCH] Add support for managed permissions

This adds support for managed permissions. The attribute list
of these is computed from the "default" (modifiable only internally),
"allowed", and "excluded" lists. This makes it possible to cleanly
merge updated IPA defaults and user changes on upgrades.

The default managed permissions are to be added in a future patch.
For now they can only be created manually (see test_managed_permissions).

Tests included.

https://fedorahosted.org/freeipa/ticket/4033
Design: http://www.freeipa.org/page/V3/Managed_Read_permissions
---
 API.txt                                        |   6 +-
 VERSION                                        |   3 +-
 ipalib/plugins/permission.py                   |  70 ++++-
 ipatests/test_xmlrpc/test_permission_plugin.py | 398 +++++++++++++++++++++++++
 4 files changed, 471 insertions(+), 6 deletions(-)

diff --git a/API.txt b/API.txt
index a6c3aed82370d690a678a034b0eea85d4f85b45f..d1690a372357d3fa59057b6290aba1d7e8853ceb 100644
--- a/API.txt
+++ b/API.txt
@@ -2378,7 +2378,7 @@ command: permission_del
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: Output('value', <type 'unicode'>, None)
 command: permission_find
-args: 1,21,4
+args: 1,22,4
 arg: Str('criteria?', noextrawhitespace=False)
 option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
 option: Str('attrs', attribute=False, autofill=False, cli_name='attrs', multivalue=True, query=True, required=False)
@@ -2386,6 +2386,7 @@ command: permission_find
 option: Str('filter', attribute=False, autofill=False, cli_name='filter', multivalue=True, query=True, required=False)
 option: Str('ipapermallowedattr', attribute=True, autofill=False, cli_name='attrs', multivalue=True, query=True, required=False)
 option: StrEnum('ipapermbindruletype', attribute=True, autofill=False, cli_name='bindtype', default=u'permission', multivalue=False, query=True, required=False, values=(u'permission', u'all', u'anonymous'))
+option: Str('ipapermexcludedattr', attribute=True, autofill=False, cli_name='excludedattrs', multivalue=True, query=True, required=False)
 option: DNOrURL('ipapermlocation', attribute=True, autofill=False, cli_name='subtree', multivalue=False, query=True, required=False)
 option: StrEnum('ipapermright', attribute=True, autofill=False, cli_name='permissions', multivalue=True, query=True, required=False, values=(u'read', u'search', u'compare', u'write', u'add', u'delete', u'all'))
 option: DNParam('ipapermtarget', attribute=True, autofill=False, cli_name='target', multivalue=False, query=True, required=False)
@@ -2406,7 +2407,7 @@ command: permission_find
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: Output('truncated', <type 'bool'>, None)
 command: permission_mod
-args: 1,22,3
+args: 1,23,3
 arg: Str('cn', attribute=True, cli_name='name', multivalue=False, pattern='^[-_ a-zA-Z0-9.]+$', primary_key=True, query=True, required=True)
 option: Str('addattr*', cli_name='addattr', exclude='webui')
 option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
@@ -2415,6 +2416,7 @@ command: permission_mod
 option: Str('filter', attribute=False, autofill=False, cli_name='filter', multivalue=True, required=False)
 option: Str('ipapermallowedattr', attribute=True, autofill=False, cli_name='attrs', multivalue=True, required=False)
 option: StrEnum('ipapermbindruletype', attribute=True, autofill=False, cli_name='bindtype', default=u'permission', multivalue=False, required=False, values=(u'permission', u'all', u'anonymous'))
+option: Str('ipapermexcludedattr', attribute=True, autofill=False, cli_name='excludedattrs', multivalue=True, required=False)
 option: DNOrURL('ipapermlocation', attribute=True, autofill=False, cli_name='subtree', multivalue=False, required=False)
 option: StrEnum('ipapermright', attribute=True, autofill=False, cli_name='permissions', multivalue=True, required=False, values=(u'read', u'search', u'compare', u'write', u'add', u'delete', u'all'))
 option: DNParam('ipapermtarget', attribute=True, autofill=False, cli_name='target', multivalue=False, required=False)
diff --git a/VERSION b/VERSION
index 5ce16b5224fd95910a221e251b2d740318bded95..9cb9d71a81bc1f1089017a2236b4b7b94946ed35 100644
--- a/VERSION
+++ b/VERSION
@@ -89,4 +89,5 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=72
+IPA_API_VERSION_MINOR=73
+# Last change: pviktori - Managed permissions
diff --git a/ipalib/plugins/permission.py b/ipalib/plugins/permission.py
index eb720131fa9b5686f17a01bf9d73da02a4675608..46b962b2e58ffcb3dcfa78a72bbfb08ee45e4f4f 100644
--- a/ipalib/plugins/permission.py
+++ b/ipalib/plugins/permission.py
@@ -79,6 +79,20 @@
 3. targetgroup: grant access to modify a specific group (such as granting
    the rights to manage group membership); sets target.
 """) + _("""
+Managed permissions
+
+Permissions that come with IPA by default can be so-called "managed"
+permissions. These have a default set of attributes they apply to.
+The user can add additional attributes to the set, or remove unwanted ones,
+with --attrs and --excluded-attributes options respectively.
+
+The resulting set is determined by taking the set of default attributes,
+adding the user-specified ones (--attrs), and then removing the
+--excluded-attributes.
+
+Deleting or renaming a managed permission, as well as changing its target,
+is not supported.
+""") + _("""
 EXAMPLES:
 """) + _("""
  Add a permission that grants the creation of users:
@@ -100,12 +114,21 @@
     'subtree': 'ipapermlocation',
 }
 
-KNOWN_FLAGS = {'SYSTEM', 'V2'}
+KNOWN_FLAGS = {'SYSTEM', 'V2', 'MANAGED'}
 
 output_params = (
     Str('aci',
         label=_('ACI'),
     ),
+    Str('ipapermdefaultattr*',
+        cli_name='defaultattrs',
+        label=_('Default attributes'),
+        doc=_('Attributes to which the permission applies by default'),
+    ),
+    Str('effectiveattr*',
+        label=_('Effective attributes'),
+        doc=_('Resulting set of attributes to which the permission applies'),
+    ),
 )
 
 
@@ -172,7 +195,15 @@ class permission(baseldap.LDAPObject):
         Str('ipapermallowedattr*',
             cli_name='attrs',
             label=_('Attributes'),
-            doc=_('Attributes to which the permission applies'),
+            doc=_('User-specified attributes to which the permission applies'),
+            flags={'allow_mod_for_managed'},
+        ),
+        Str('ipapermexcludedattr*',
+            cli_name='excludedattrs',
+            label=_('Excluded attributes'),
+            doc=_('Attributes to which the permission explicitly '
+                  'does not apply'),
+            flags={'no_create', 'allow_mod_for_managed'},
         ),
         StrEnum(
             'ipapermbindruletype',
@@ -182,6 +213,7 @@ class permission(baseldap.LDAPObject):
             autofill=True,
             values=(u'permission', u'all', u'anonymous'),
             default=u'permission',
+            flags={'allow_mod_for_managed'},
         ),
         DNOrURL(
             'ipapermlocation?',
@@ -319,6 +351,9 @@ def postprocess_result(self, entry, options):
                     raise
             else:
                 entry.single_value['aci'] = acistring
+        else:
+            if 'MANAGED' in entry.get('ipapermissiontype', ()):
+                entry['effectiveattr'] = self.get_effective_attrs(entry)
 
         if not client_has_capability(options['version'], 'permissions2'):
             # Legacy clients expect some attributes as a single value
@@ -337,6 +372,12 @@ def postprocess_result(self, entry, options):
                     new_filter.append(flt[1:-1])
                 entry['filter'] = new_filter
 
+    def get_effective_attrs(self, entry):
+        attrs = set(entry.get('ipapermdefaultattr', ()))
+        attrs.update(entry.get('ipapermallowedattr', ()))
+        attrs.difference_update(entry.get('ipapermexcludedattr', ()))
+        return sorted(attrs)
+
     def make_aci(self, entry):
         """Make an ACI string from the given permission entry"""
 
@@ -362,7 +403,7 @@ def make_aci(self, entry):
         else:
             raise ValueError(ipapermbindruletype)
         aci.permissions = entry['ipapermright']
-        aci.set_target_attr(entry.get('ipapermallowedattr', []))
+        aci.set_target_attr(self.get_effective_attrs(entry))
 
         return aci.export_to_string()
 
@@ -738,6 +779,9 @@ def pre_callback(self, ldap, dn, *keys, **options):
 
         if not options.get('force'):
             self.obj.reject_system(entry)
+            if entry.get('ipapermdefaultattr'):
+                raise errors.ACIError(
+                    info=_('cannot delete managed permissions'))
 
         try:
             self.obj.remove_aci(entry)
@@ -776,6 +820,26 @@ def pre_callback(self, ldap, dn, entry, attrs_list, *keys, **options):
         self.obj.reject_system(old_entry)
         self.obj.upgrade_permission(old_entry)
 
+        if 'MANAGED' in old_entry.get('ipapermissiontype', ()):
+            for option_name in sorted(options):
+                if option_name == 'rename':
+                    raise errors.ValidationError(
+                        name=option_name,
+                        error=_('cannot rename managed permissions'))
+                option = self.options[option_name]
+                allow_mod = 'allow_mod_for_managed' in option.flags
+                if option.attribute and not allow_mod:
+                    raise errors.ValidationError(
+                        name=option_name,
+                        error=_('not modifiable on managed permissions'))
+        else:
+            if options.get('ipapermexcludedattr'):
+                # prevent setting excluded attributes on normal permissions
+                # (but do allow deleting them all)
+                raise errors.ValidationError(
+                    name='ipapermexcludedattr',
+                    error=_('only available on managed permissions'))
+
         # Check setting bindtype for an assigned permission
         if options.get('ipapermbindruletype') and old_entry.get('member'):
             raise errors.ValidationError(
diff --git a/ipatests/test_xmlrpc/test_permission_plugin.py b/ipatests/test_xmlrpc/test_permission_plugin.py
index 6564cbc9b5da4adfe582a753947d7fccdbbf4cb1..265e5c61a957c6bff3617d7fb57f6de55aa1d752 100644
--- a/ipatests/test_xmlrpc/test_permission_plugin.py
+++ b/ipatests/test_xmlrpc/test_permission_plugin.py
@@ -24,12 +24,22 @@
 
 import os
 
+import nose
+
 from ipalib import api, errors
 from ipatests.test_xmlrpc import objectclasses
 from xmlrpc_test import Declarative
 from ipapython.dn import DN
 import inspect
 
+try:
+    from ipaserver.plugins.ldap2 import ldap2
+except ImportError:
+    have_ldap2 = False
+else:
+    import krbV
+    have_ldap2 = True
+
 permission1 = u'testperm'
 permission1_dn = DN(('cn',permission1),
                     api.env.container_permission,api.env.basedn)
@@ -283,6 +293,18 @@ class test_permission_negative(Declarative):
                 error='May only contain letters, numbers, -, _, ., and space'),
         ),
 
+        dict(
+            desc='Try setting ipapermexcludedattrs on %r' % permission1,
+            command=(
+                'permission_mod', [permission1], dict(
+                    ipapermexcludedattr=[u'cn'],
+                )
+            ),
+            expected=errors.ValidationError(
+                name='ipapermexcludedattr',
+                error='only available on managed permissions'),
+        ),
+
     ]
 
 
@@ -2422,3 +2444,379 @@ class test_permission_bindtype(Declarative):
                     'assigned to a privilege')
         ),
     ]
+
+
+class test_managed_permissions(Declarative):
+    cleanup_commands = [
+        ('permission_del', [permission1], {'force': True}),
+        ('permission_del', [permission2], {'force': True}),
+    ]
+
+    @classmethod
+    def setUpClass(cls):
+        super(test_managed_permissions, cls).setUpClass()
+
+        if not have_ldap2:
+            raise nose.SkipTest('server plugin not available')
+
+    def add_managed_permission(self):
+        """Add a managed permission and the corresponding ACI"""
+        ldap = ldap2(shared_instance=False)
+        ldap.connect(ccache=krbV.default_context().default_ccache())
+
+        result = api.Command.permission_add(permission1, type=u'user',
+                                            ipapermright=u'write',
+                                            ipapermallowedattr=[u'cn'])
+
+        # TODO: This hack relies on the permission internals.
+        # Change as necessary.
+
+        # Add permission DN
+        entry = ldap.get_entry(permission1_dn)
+        entry['ipapermdefaultattr'] = ['l', 'o', 'cn']
+        ldap.update_entry(entry)
+
+        # Update the ACI via the API
+        result = api.Command.permission_mod(permission1,
+                                            ipapermallowedattr=None)
+
+        # Set the permission type to MANAGED
+        entry = ldap.get_entry(permission1_dn)
+        entry['ipapermissiontype'].append('MANAGED')
+        ldap.update_entry(entry)
+
+    tests = [
+        add_managed_permission,
+
+        dict(
+            desc='Show pre-created %r' % permission1,
+            command=('permission_show', [permission1], {'all': True}),
+            expected=dict(
+                value=permission1,
+                summary=None,
+                result=dict(
+                    dn=permission1_dn,
+                    cn=[permission1],
+                    objectclass=objectclasses.permission,
+                    ipapermissiontype=[u'SYSTEM', u'V2', u'MANAGED'],
+                    type=[u'user'],
+                    ipapermright=[u'write'],
+                    ipapermbindruletype=[u'permission'],
+                    ipapermlocation=[users_dn],
+                    ipapermtarget=[DN(('uid', '*'), users_dn)],
+                    ipapermdefaultattr=[u'l', u'o', u'cn'],
+                    effectiveattr=[u'l', u'o', u'cn'],
+                ),
+            ),
+        ),
+
+        verify_permission_aci(
+            permission1, users_dn,
+            '(targetattr = "cn || l || o")' +
+            '(target = "ldap:///%s";)' % DN(('uid', '*'), users_dn) +
+            '(version 3.0;acl "permission:%s";' % permission1 +
+            'allow (write) groupdn = "ldap:///%s";;)' % permission1_dn,
+        ),
+
+    ] + [
+        # Verify that most permission attributes can't be changed
+        dict(
+            desc='Try to modify %s in %r' % (attr_name, permission1),
+            command=('permission_mod', [permission1],
+                     {attr_name: value}),
+            expected=errors.ValidationError(
+                name=err_attr or attr_name,
+                error='not modifiable on managed permissions'),
+        )
+        for attr_name, err_attr, value in (
+            ('ipapermlocation', None, users_dn),
+            ('ipapermright', None, u'compare'),
+            ('ipapermtarget', None, users_dn),
+            ('ipapermtargetfilter', None, u'(ou=engineering)'),
+
+            ('memberof', 'ipapermtargetfilter', u'admins'),
+            ('targetgroup', 'ipapermtarget', u'admins'),
+            ('type', 'ipapermlocation', u'group'),
+        )
+    ] + [
+
+        dict(
+            desc='Try to rename %r' % permission1,
+            command=('permission_mod', [permission1],
+                     {'rename': permission2}),
+            expected=errors.ValidationError(
+                name='rename',
+                error='cannot rename managed permissions'),
+        ),
+
+        verify_permission_aci(
+            permission1, users_dn,
+            '(targetattr = "cn || l || o")' +
+            '(target = "ldap:///%s";)' % DN(('uid', '*'), users_dn) +
+            '(version 3.0;acl "permission:%s";' % permission1 +
+            'allow (write) groupdn = "ldap:///%s";;)' % permission1_dn,
+        ),
+
+        dict(
+            desc='Modify allowed and excluded attrs in %r' % permission1,
+            command=('permission_mod', [permission1],
+                     {'ipapermallowedattr': [u'dc'],
+                      'ipapermexcludedattr': [u'cn'],
+                      'all': True}),
+            expected=dict(
+                value=permission1,
+                summary=u'Modified permission "testperm"',
+                result=dict(
+                    dn=permission1_dn,
+                    cn=[permission1],
+                    objectclass=objectclasses.permission,
+                    ipapermissiontype=[u'SYSTEM', u'V2', u'MANAGED'],
+                    type=[u'user'],
+                    ipapermright=[u'write'],
+                    ipapermbindruletype=[u'permission'],
+                    ipapermlocation=[users_dn],
+                    ipapermtarget=[DN(('uid', '*'), users_dn)],
+                    ipapermdefaultattr=[u'l', u'o', u'cn'],
+                    effectiveattr=[u'l', u'o', u'dc'],
+                    ipapermallowedattr=[u'dc'],
+                    ipapermexcludedattr=[u'cn'],
+                ),
+            ),
+        ),
+
+        verify_permission_aci(
+            permission1, users_dn,
+            '(targetattr = "dc || l || o")' +
+            '(target = "ldap:///%s";)' % DN(('uid', '*'), users_dn) +
+            '(version 3.0;acl "permission:%s";' % permission1 +
+            'allow (write) groupdn = "ldap:///%s";;)' % permission1_dn,
+        ),
+
+        dict(
+            desc='Modify allowed attrs in %r' % permission1,
+            command=('permission_mod', [permission1],
+                     {'ipapermallowedattr': [u'cn', u'sn'],
+                      'all': True}),
+            expected=dict(
+                value=permission1,
+                summary=u'Modified permission "testperm"',
+                result=dict(
+                    dn=permission1_dn,
+                    cn=[permission1],
+                    objectclass=objectclasses.permission,
+                    ipapermissiontype=[u'SYSTEM', u'V2', u'MANAGED'],
+                    type=[u'user'],
+                    ipapermright=[u'write'],
+                    ipapermbindruletype=[u'permission'],
+                    ipapermlocation=[users_dn],
+                    ipapermtarget=[DN(('uid', '*'), users_dn)],
+                    ipapermdefaultattr=[u'l', u'o', u'cn'],
+                    effectiveattr=[u'l', u'o', u'sn'],
+                    ipapermallowedattr=[u'cn', u'sn'],
+                    ipapermexcludedattr=[u'cn'],
+                ),
+            ),
+        ),
+
+        verify_permission_aci(
+            permission1, users_dn,
+            '(targetattr = "l || o || sn")' +
+            '(target = "ldap:///%s";)' % DN(('uid', '*'), users_dn) +
+            '(version 3.0;acl "permission:%s";' % permission1 +
+            'allow (write) groupdn = "ldap:///%s";;)' % permission1_dn,
+        ),
+
+        dict(
+            desc='Add ineffective allowed attr to %r' % permission1,
+            command=('permission_mod', [permission1],
+                     {'ipapermallowedattr': [u'cn', u'sn', u'o'],
+                      'all': True}),
+            expected=dict(
+                value=permission1,
+                summary=u'Modified permission "testperm"',
+                result=dict(
+                    dn=permission1_dn,
+                    cn=[permission1],
+                    objectclass=objectclasses.permission,
+                    ipapermissiontype=[u'SYSTEM', u'V2', u'MANAGED'],
+                    type=[u'user'],
+                    ipapermright=[u'write'],
+                    ipapermbindruletype=[u'permission'],
+                    ipapermlocation=[users_dn],
+                    ipapermtarget=[DN(('uid', '*'), users_dn)],
+                    ipapermdefaultattr=[u'l', u'o', u'cn'],
+                    effectiveattr=[u'l', u'o', u'sn'],
+                    ipapermallowedattr=[u'cn', u'sn', u'o'],
+                    ipapermexcludedattr=[u'cn'],
+                ),
+            ),
+        ),
+
+        verify_permission_aci(
+            permission1, users_dn,
+            '(targetattr = "l || o || sn")' +
+            '(target = "ldap:///%s";)' % DN(('uid', '*'), users_dn) +
+            '(version 3.0;acl "permission:%s";' % permission1 +
+            'allow (write) groupdn = "ldap:///%s";;)' % permission1_dn,
+        ),
+
+        dict(
+            desc='Modify excluded attrs in %r' % permission1,
+            command=('permission_mod', [permission1],
+                     {'ipapermexcludedattr': [u'cn', u'sn'],
+                      'all': True}),
+            expected=dict(
+                value=permission1,
+                summary=u'Modified permission "testperm"',
+                result=dict(
+                    dn=permission1_dn,
+                    cn=[permission1],
+                    objectclass=objectclasses.permission,
+                    ipapermissiontype=[u'SYSTEM', u'V2', u'MANAGED'],
+                    type=[u'user'],
+                    ipapermright=[u'write'],
+                    ipapermbindruletype=[u'permission'],
+                    ipapermlocation=[users_dn],
+                    ipapermtarget=[DN(('uid', '*'), users_dn)],
+                    ipapermdefaultattr=[u'l', u'o', u'cn'],
+                    effectiveattr=[u'l', u'o'],
+                    ipapermallowedattr=[u'cn', u'sn', u'o'],
+                    ipapermexcludedattr=[u'cn', u'sn'],
+                ),
+            ),
+        ),
+
+        verify_permission_aci(
+            permission1, users_dn,
+            '(targetattr = "l || o")' +
+            '(target = "ldap:///%s";)' % DN(('uid', '*'), users_dn) +
+            '(version 3.0;acl "permission:%s";' % permission1 +
+            'allow (write) groupdn = "ldap:///%s";;)' % permission1_dn,
+        ),
+
+        dict(
+            desc='Modify bind rule in %r' % permission1,
+            command=('permission_mod', [permission1],
+                     {'ipapermbindruletype': u'all'}),
+            expected=dict(
+                value=permission1,
+                summary=u'Modified permission "testperm"',
+                result=dict(
+                    dn=permission1_dn,
+                    cn=[permission1],
+                    objectclass=objectclasses.permission,
+                    ipapermissiontype=[u'SYSTEM', u'V2', u'MANAGED'],
+                    type=[u'user'],
+                    ipapermright=[u'write'],
+                    ipapermbindruletype=[u'all'],
+                    ipapermlocation=[users_dn],
+                    ipapermtarget=[DN(('uid', '*'), users_dn)],
+                    ipapermdefaultattr=[u'l', u'o', u'cn'],
+                    effectiveattr=[u'l', u'o'],
+                    ipapermallowedattr=[u'cn', u'sn', u'o'],
+                    ipapermexcludedattr=[u'cn', u'sn'],
+                ),
+            ),
+        ),
+
+        verify_permission_aci(
+            permission1, users_dn,
+            '(targetattr = "l || o")' +
+            '(target = "ldap:///%s";)' % DN(('uid', '*'), users_dn) +
+            '(version 3.0;acl "permission:%s";' % permission1 +
+            'allow (write) userdn = "ldap:///all";;)',
+        ),
+
+        dict(
+            desc='Show %r with no options' % permission1,
+            command=('permission_show', [permission1], {}),
+            expected=dict(
+                value=permission1,
+                summary=None,
+                result=dict(
+                    dn=permission1_dn,
+                    cn=[permission1],
+                    objectclass=objectclasses.permission,
+                    ipapermissiontype=[u'SYSTEM', u'V2', u'MANAGED'],
+                    type=[u'user'],
+                    ipapermright=[u'write'],
+                    ipapermbindruletype=[u'all'],
+                    ipapermlocation=[users_dn],
+                    ipapermtarget=[DN(('uid', '*'), users_dn)],
+                    ipapermdefaultattr=[u'l', u'o', u'cn'],
+                    effectiveattr=[u'l', u'o'],
+                    ipapermallowedattr=[u'cn', u'sn', u'o'],
+                    ipapermexcludedattr=[u'cn', u'sn'],
+                ),
+            ),
+        ),
+
+        dict(
+            desc='Show %r with --all' % permission1,
+            command=('permission_show', [permission1], {'all': True}),
+            expected=dict(
+                value=permission1,
+                summary=None,
+                result=dict(
+                    dn=permission1_dn,
+                    cn=[permission1],
+                    objectclass=objectclasses.permission,
+                    ipapermissiontype=[u'SYSTEM', u'V2', u'MANAGED'],
+                    type=[u'user'],
+                    ipapermright=[u'write'],
+                    ipapermbindruletype=[u'all'],
+                    ipapermlocation=[users_dn],
+                    ipapermtarget=[DN(('uid', '*'), users_dn)],
+                    ipapermdefaultattr=[u'l', u'o', u'cn'],
+                    effectiveattr=[u'l', u'o'],
+                    ipapermallowedattr=[u'cn', u'sn', u'o'],
+                    ipapermexcludedattr=[u'cn', u'sn'],
+                ),
+            ),
+        ),
+
+        dict(
+            desc='Show %r with --raw' % permission1,
+            command=('permission_show', [permission1], {'raw': True}),
+            expected=dict(
+                value=permission1,
+                summary=None,
+                result=dict(
+                    dn=permission1_dn,
+                    cn=[permission1],
+                    aci=['(targetattr = "l || o")'
+                         '(target = "ldap:///%(tdn)s")'
+                         '(version 3.0;acl "permission:%(name)s";'
+                         'allow (write) userdn = "ldap:///all";;)' %
+                         {'tdn': DN(('uid', '*'), users_dn),
+                          'name': permission1}],
+                    objectclass=objectclasses.permission,
+                    ipapermissiontype=[u'SYSTEM', u'V2', u'MANAGED'],
+                    ipapermright=[u'write'],
+                    ipapermbindruletype=[u'all'],
+                    ipapermlocation=[users_dn],
+                    ipapermtarget=[DN(('uid', '*'), users_dn)],
+                    ipapermdefaultattr=[u'l', u'o', u'cn'],
+                    ipapermallowedattr=[u'cn', u'sn', u'o'],
+                    ipapermexcludedattr=[u'cn', u'sn'],
+                ),
+            ),
+        ),
+
+        dict(
+            desc='Try to delete %r' % permission1,
+            command=('permission_del', [permission1], {}),
+            expected=errors.ACIError(
+                info='cannot delete managed permissions'),
+        ),
+
+        dict(
+            desc='Delete %r with --force' % permission1,
+            command=('permission_del', [permission1], {'force': True}),
+            expected=dict(
+                result=dict(failed=u''),
+                value=permission1,
+                summary=u'Deleted permission "%s"' % permission1,
+            ),
+        ),
+    ]
-- 
1.8.4.2

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to