diff options
author | Petr Viktorin <pviktori@redhat.com> | 2014-03-04 16:59:33 +0100 |
---|---|---|
committer | Martin Kosek <mkosek@redhat.com> | 2014-03-14 10:14:05 +0100 |
commit | f58ffe176c57d01274888638d637b230c1081a60 (patch) | |
tree | 92d4350964ce9e949359b37aa7dbbef5c5284ed1 /ipalib/plugins/permission.py | |
parent | 3120a6833e71d28fb0dcbbd62190b5f9c2e2c466 (diff) | |
download | freeipa-f58ffe176c57d01274888638d637b230c1081a60.tar.gz freeipa-f58ffe176c57d01274888638d637b230c1081a60.tar.xz freeipa-f58ffe176c57d01274888638d637b230c1081a60.zip |
permission plugin: Write support for extratargetfilter
Extend the permission-add and permission-mod commands to process
extratargetfilter.
Part of the work for: https://fedorahosted.org/freeipa/ticket/4216
Reviewed-By: Martin Kosek <mkosek@redhat.com>
Diffstat (limited to 'ipalib/plugins/permission.py')
-rw-r--r-- | ipalib/plugins/permission.py | 135 |
1 files changed, 88 insertions, 47 deletions
diff --git a/ipalib/plugins/permission.py b/ipalib/plugins/permission.py index d8eeea28b..7dde36d62 100644 --- a/ipalib/plugins/permission.py +++ b/ipalib/plugins/permission.py @@ -285,6 +285,61 @@ class permission(baseldap.LDAPObject): raise errors.ACIError( info=_('A SYSTEM permission may not be modified or removed')) + def _get_filter_attr_info(self, entry): + """Get information on filter-related virtual attributes + + Returns a dict with this information: + 'implicit_targetfilters': targetfilters implied by memberof and type + 'memberof': list of names of groups from memberof + 'type': the type + """ + ipapermtargetfilter = entry.get('ipapermtargetfilter', []) + ipapermlocation = entry.single_value.get('ipapermlocation') + + implicit_targetfilters = set() + result = {'implicit_targetfilters': implicit_targetfilters} + + # memberof + memberof = [] + for targetfilter in ipapermtargetfilter: + match = re.match('^\(memberof=(.*)\)$', targetfilter, re.I) + if match: + dn = DN(match.group(1)) + groups_dn = DN(self.api.Object.group.container_dn, + self.api.env.basedn) + if dn[1:] == groups_dn[:] and dn[0].attr == 'cn': + memberof.append(dn[0].value) + implicit_targetfilters.add(match.group(0)) + if memberof: + result['memberof'] = memberof + + # type + if ipapermtargetfilter and ipapermlocation: + for obj in self.api.Object(): + filter_objectclasses = getattr( + obj, 'permission_filter_objectclasses', None) + if not filter_objectclasses: + continue + wantdn = DN(obj.container_dn, self.api.env.basedn) + if DN(ipapermlocation) != wantdn: + continue + + objectclass_targetfilters = set() + for objclass in filter_objectclasses: + filter_re = '\(objectclass=%s\)' % re.escape(objclass) + for tf in ipapermtargetfilter: + if re.match(filter_re, tf, re.I): + objectclass_targetfilters.add(tf) + break + else: + break + else: + result['type'] = [unicode(obj.name)] + implicit_targetfilters |= objectclass_targetfilters + break + + return result + def postprocess_result(self, entry, options): """Update a permission entry for output (in place) @@ -299,23 +354,6 @@ class permission(baseldap.LDAPObject): if not options.get('raw') and not options.get('pkey_only'): ipapermtargetfilter = entry.get('ipapermtargetfilter', []) ipapermtarget = entry.single_value.get('ipapermtarget') - ipapermlocation = entry.single_value.get('ipapermlocation') - - implicit_targetfilters = set() - - # memberof - memberof = [] - for targetfilter in ipapermtargetfilter: - match = re.match('^\(memberof=(.*)\)$', targetfilter, re.I) - if match: - dn = DN(match.group(1)) - groups_dn = DN(self.api.Object.group.container_dn, - self.api.env.basedn) - if dn[1:] == groups_dn[:] and dn[0].attr == 'cn': - memberof.append(dn[0].value) - implicit_targetfilters.add(match.group(0)) - if memberof: - entry['memberof'] = memberof # targetgroup if ipapermtarget: @@ -325,34 +363,15 @@ class permission(baseldap.LDAPObject): dn[0].attr == 'cn' and dn[0].value != '*'): entry.single_value['targetgroup'] = dn[0].value - # type - if ipapermtargetfilter and ipapermlocation: - for obj in self.api.Object(): - filter_objectclasses = getattr( - obj, 'permission_filter_objectclasses', None) - if not filter_objectclasses: - continue - wantdn = DN(obj.container_dn, self.api.env.basedn) - if DN(ipapermlocation) != wantdn: - continue - - objectclass_targetfilters = set() - for objclass in filter_objectclasses: - filter_re = '\(objectclass=%s\)' % re.escape(objclass) - for tf in ipapermtargetfilter: - if re.match(filter_re, tf, re.I): - objectclass_targetfilters.add(tf) - break - else: - break - else: - entry.single_value['type'] = unicode(obj.name) - implicit_targetfilters |= objectclass_targetfilters - break - - if ipapermtargetfilter: + filter_attr_info = self._get_filter_attr_info(entry) + if 'type' in filter_attr_info: + entry['type'] = filter_attr_info['type'] + if 'memberof' in filter_attr_info: + entry['memberof'] = filter_attr_info['memberof'] + if 'implicit_targetfilters' in filter_attr_info: extratargetfilter = sorted( - set(ipapermtargetfilter) - implicit_targetfilters) + set(ipapermtargetfilter) - + filter_attr_info['implicit_targetfilters']) if extratargetfilter: entry['extratargetfilter'] = extratargetfilter @@ -652,7 +671,9 @@ class permission(baseldap.LDAPObject): raise ValueError('Cannot convert ACI, %r != %r' % (new_acistring, acistring)) - def preprocess_options(self, options, return_filter_ops=False): + def preprocess_options(self, options, + return_filter_ops=False, + merge_targetfilter=False): """Preprocess options (in-place) :param options: A dictionary of options @@ -667,8 +688,19 @@ class permission(baseldap.LDAPObject): - remove: list of regular expression objects; values that match any of them sould be removed - add: list of values to be added, after any removals + :merge_targetfilter: + If true, the extratargetfilter is copied into ipapermtargetfilter. """ + if 'extratargetfilter' in options: + if 'ipapermtargetfilter' in options: + raise errors.ValidationError( + name='ipapermtargetfilter', + error=_('cannot specify full target filter ' + 'and extra target filter simultaneously')) + if merge_targetfilter: + options['ipapermtargetfilter'] = options['extratargetfilter'] + filter_ops = {'add': [], 'remove': []} if options.get('subtree'): @@ -836,7 +868,7 @@ class permission_add(baseldap.LDAPCreate): # Need to override execute so that processed options apply to # the whole command, not just the callbacks def execute(self, *keys, **options): - self.obj.preprocess_options(options) + self.obj.preprocess_options(options, merge_targetfilter=True) return super(permission_add, self).execute(*keys, **options) def pre_callback(self, ldap, dn, entry, attrs_list, *keys, **options): @@ -950,7 +982,8 @@ class permission_mod(baseldap.LDAPUpdate): error=_('cannot rename managed permissions')) option = self.options[option_name] allow_mod = 'allow_mod_for_managed_permission' in option.flags - if option.attribute and not allow_mod: + if (option.attribute and not allow_mod or + option_name == 'extratargetfilter'): raise errors.ValidationError( name=option_name, error=_('not modifiable on managed permissions')) @@ -994,6 +1027,14 @@ class permission_mod(baseldap.LDAPUpdate): key not in self.obj.attribute_members): entry.setdefault(key, value) + # For extratargetfilter, add it to the implicit filters + # to get the full target filter + if 'extratargetfilter' in options: + filter_attr_info = self.obj._get_filter_attr_info(entry) + entry['ipapermtargetfilter'] = ( + list(options['extratargetfilter'] or []) + + list(filter_attr_info['implicit_targetfilters'])) + filter_ops = context.filter_ops removes = filter_ops.get('remove', []) new_filters = set( |