summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Viktorin <pviktori@redhat.com>2013-09-19 17:41:04 +0200
committerPetr Viktorin <pviktori@redhat.com>2014-03-25 14:18:12 +0100
commitf4de4a2aa75db990c787b7a8dbc6b3bdd7e01a06 (patch)
tree02d799adcab253b8d0b6c6a629283ca01150bbcc
parent1df9b5836ad26bab3513b726305f5e061424e2c9 (diff)
downloadfreeipa-f4de4a2aa75db990c787b7a8dbc6b3bdd7e01a06.tar.gz
freeipa-f4de4a2aa75db990c787b7a8dbc6b3bdd7e01a06.tar.xz
freeipa-f4de4a2aa75db990c787b7a8dbc6b3bdd7e01a06.zip
Add Object metadata and update plugin for managed permissions
The default read permission is added for Netgroup as an example. Part of the work for: https://fedorahosted.org/freeipa/ticket/3566 Design: http://www.freeipa.org/page/V3/Managed_Read_permissions Reviewed-By: Martin Kosek <mkosek@redhat.com>
-rw-r--r--ipalib/plugins/baseldap.py1
-rw-r--r--ipalib/plugins/netgroup.py19
-rw-r--r--ipaserver/install/plugins/update_managed_permissions.py160
3 files changed, 180 insertions, 0 deletions
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index c4951eb56..6a8b4f822 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -469,6 +469,7 @@ class LDAPObject(Object):
}
label = _('Entry')
label_singular = _('Entry')
+ managed_permissions = {}
container_not_found_msg = _('container entry (%(container)s) not found')
parent_not_found_msg = _('%(parent)s: %(oname)s not found')
diff --git a/ipalib/plugins/netgroup.py b/ipalib/plugins/netgroup.py
index fe27e6cb6..7136c18f9 100644
--- a/ipalib/plugins/netgroup.py
+++ b/ipalib/plugins/netgroup.py
@@ -105,6 +105,25 @@ class netgroup(LDAPObject):
'memberuser': ('Member', '', 'no_'),
'memberhost': ('Member', '', 'no_'),
}
+ managed_permissions = {
+ 'System: Read Netgroups': {
+ 'replaces_global_anonymous_aci': True,
+ 'ipapermbindruletype': 'all',
+ 'ipapermright': {'read', 'search', 'compare'},
+ 'ipapermdefaultattr': {
+ 'cn', 'description', 'hostcategory', 'ipaenabledflag',
+ 'ipauniqueid', 'nisdomainname', 'usercategory'
+ },
+ },
+ 'System: Read Netgroup Membership': {
+ 'replaces_global_anonymous_aci': True,
+ 'ipapermbindruletype': 'all',
+ 'ipapermright': {'read', 'search', 'compare'},
+ 'ipapermdefaultattr': {
+ 'externalhost', 'member', 'memberof', 'memberuser'
+ },
+ },
+ }
label = _('Netgroups')
label_singular = _('Netgroup')
diff --git a/ipaserver/install/plugins/update_managed_permissions.py b/ipaserver/install/plugins/update_managed_permissions.py
new file mode 100644
index 000000000..603f3f0b7
--- /dev/null
+++ b/ipaserver/install/plugins/update_managed_permissions.py
@@ -0,0 +1,160 @@
+# Authors:
+# Petr Viktorin <pviktori@redhat.com>
+#
+# Copyright (C) 2014 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from ipalib import errors
+from ipapython.dn import DN
+from ipalib.plugable import Registry
+from ipalib.plugins import aci
+from ipalib.plugins.permission import permission
+from ipaserver.plugins.ldap2 import ldap2
+from ipaserver.install.plugins import LAST
+from ipaserver.install.plugins.baseupdate import PostUpdate
+
+
+register = Registry()
+
+
+@register()
+class update_managed_permissions(PostUpdate):
+ """Update managed permissions after an update.
+
+ Update managed permissions according to templates specified in plugins.
+ For read permissions, puts any attributes specified in the legacy
+ Anonymous access ACI in the exclude list when creating the permission.
+ """
+ order = LAST
+
+ def get_anonymous_read_blacklist(self, ldap):
+ """Get the list of attributes from the legacy anonymous access ACI"""
+ aciname = u'Enable Anonymous access'
+ aciprefix = u'none'
+
+ base_entry = ldap.get_entry(self.api.env.basedn, ['aci'])
+
+ acistrs = base_entry.get('aci', [])
+ acilist = aci._convert_strings_to_acis(acistrs)
+ try:
+ rawaci = aci._find_aci_by_name(acilist, aciprefix, aciname)
+ except errors.NotFound:
+ self.log.info('Anonymous ACI not found, using no blacklist')
+ return []
+
+ return rawaci.target['targetattr']['expression']
+
+ def execute(self, **options):
+ ldap = self.api.Backend[ldap2]
+
+ anonymous_read_blacklist = self.get_anonymous_read_blacklist(ldap)
+
+ self.log.info('Anonymous read blacklist: %s', anonymous_read_blacklist)
+
+ for obj in self.api.Object():
+ managed_permissions = getattr(obj, 'managed_permissions', {})
+ if managed_permissions:
+ self.log.info('Updating managed permissions for %s', obj.name)
+ for name, template in managed_permissions.items():
+ assert name.startswith('System:')
+ self.update_permission(ldap,
+ obj,
+ unicode(name),
+ template,
+ anonymous_read_blacklist)
+
+ return False, False, ()
+
+ def update_permission(self, ldap, obj, name, template,
+ anonymous_read_blacklist):
+ """Update the given permission and the corresponding ACI"""
+ dn = self.api.Object[permission].get_dn(name)
+
+ try:
+ attrs_list = self.api.Object[permission].default_attributes
+ entry = ldap.get_entry(dn, attrs_list)
+ is_new = False
+ except errors.NotFound:
+ entry = ldap.make_entry(dn)
+ is_new = True
+
+ self.log.info('Updating managed permission: %s', name)
+ self.update_entry(obj, entry, template,
+ anonymous_read_blacklist, is_new=is_new)
+
+ if is_new:
+ ldap.add_entry(entry)
+ else:
+ try:
+ ldap.update_entry(entry)
+ except errors.EmptyModlist:
+ self.log.debug('No changes to permission: %s', name)
+ return
+
+ self.log.debug('Updating ACI for managed permission: %s', name)
+
+ self.api.Object[permission].update_aci(entry)
+
+ def update_entry(self, obj, entry, template,
+ anonymous_read_blacklist, is_new):
+ """Update the given permission Entry (without contacting LDAP)"""
+
+ [name_ava] = entry.dn[0]
+ assert name_ava.attr == 'cn'
+ name = name_ava.value
+ entry.single_value['cn'] = name
+
+ template = dict(template)
+
+ # Common attributes
+ entry['objectclass'] = self.api.Object[permission].object_class
+
+ entry['ipapermissiontype'] = [u'SYSTEM', u'V2', u'MANAGED']
+
+ # Object-specific attributes
+ ldap_filter = ['(objectclass=%s)' % oc
+ for oc in obj.permission_filter_objectclasses]
+ entry['ipapermtargetfilter'] = ldap_filter
+
+ ipapermlocation = DN(obj.container_dn, self.api.env.basedn)
+ entry.single_value['ipapermlocation'] = ipapermlocation
+
+ # Attributes from template
+ bindruletype = template.pop('ipapermbindruletype')
+ entry.single_value['ipapermbindruletype'] = bindruletype
+
+ entry['ipapermright'] = list(template.pop('ipapermright'))
+
+ # Add to the set of default attributes
+ attributes = set(template.pop('ipapermdefaultattr', ()))
+ attributes.update(entry.get('ipapermdefaultattr', ()))
+ attributes = set(a.lower() for a in attributes)
+ entry['ipapermdefaultattr'] = list(attributes)
+
+ # Exclude attributes filtered from the global read ACI
+ if template.pop('replaces_global_anonymous_aci', False) and is_new:
+ read_blacklist = set(a.lower() for a in anonymous_read_blacklist)
+ read_blacklist &= attributes
+ if read_blacklist:
+ self.log.info('Excluded attributes for %s: %s',
+ name, ', '.join(read_blacklist))
+ entry['ipapermexcludedattr'] = list(read_blacklist)
+
+ # Sanity check
+ if template:
+ raise ValueError(
+ 'Unknown key(s) in managed permission template %s: %s' % (
+ name, ', '.join(template.keys())))