summaryrefslogtreecommitdiffstats
path: root/ipaserver/plugins/netgroup.py
diff options
context:
space:
mode:
authorJan Cholasta <jcholast@redhat.com>2016-04-28 10:30:05 +0200
committerJan Cholasta <jcholast@redhat.com>2016-06-03 09:00:34 +0200
commit6e44557b601f769d23ee74555a72e8b5cc62c0c9 (patch)
treeeedd3e054b0709341b9f58c190ea54f999f7d13a /ipaserver/plugins/netgroup.py
parentec841e5d7ab29d08de294b3fa863a631cd50e30a (diff)
downloadfreeipa-6e44557b601f769d23ee74555a72e8b5cc62c0c9.tar.gz
freeipa-6e44557b601f769d23ee74555a72e8b5cc62c0c9.tar.xz
freeipa-6e44557b601f769d23ee74555a72e8b5cc62c0c9.zip
ipalib: move server-side plugins to ipaserver
Move the remaining plugin code from ipalib.plugins to ipaserver.plugins. Remove the now unused ipalib.plugins package. https://fedorahosted.org/freeipa/ticket/4739 Reviewed-By: David Kupka <dkupka@redhat.com>
Diffstat (limited to 'ipaserver/plugins/netgroup.py')
-rw-r--r--ipaserver/plugins/netgroup.py387
1 files changed, 387 insertions, 0 deletions
diff --git a/ipaserver/plugins/netgroup.py b/ipaserver/plugins/netgroup.py
new file mode 100644
index 000000000..f76a0ba3a
--- /dev/null
+++ b/ipaserver/plugins/netgroup.py
@@ -0,0 +1,387 @@
+# Authors:
+# Rob Crittenden <rcritten@redhat.com>
+# Pavel Zuna <pzuna@redhat.com>
+#
+# Copyright (C) 2009 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/>.
+
+import six
+
+from ipalib import api, errors
+from ipalib import Str, StrEnum, Flag
+from ipalib.plugable import Registry
+from .baseldap import (
+ external_host_param,
+ add_external_pre_callback,
+ add_external_post_callback,
+ remove_external_post_callback,
+ LDAPObject,
+ LDAPCreate,
+ LDAPDelete,
+ LDAPUpdate,
+ LDAPSearch,
+ LDAPRetrieve,
+ LDAPAddMember,
+ LDAPRemoveMember)
+from ipalib import _, ngettext
+from .hbacrule import is_all
+from ipapython.dn import DN
+
+if six.PY3:
+ unicode = str
+
+__doc__ = _("""
+Netgroups
+
+A netgroup is a group used for permission checking. It can contain both
+user and host values.
+
+EXAMPLES:
+
+ Add a new netgroup:
+ ipa netgroup-add --desc="NFS admins" admins
+
+ Add members to the netgroup:
+ ipa netgroup-add-member --users=tuser1 --users=tuser2 admins
+
+ Remove a member from the netgroup:
+ ipa netgroup-remove-member --users=tuser2 admins
+
+ Display information about a netgroup:
+ ipa netgroup-show admins
+
+ Delete a netgroup:
+ ipa netgroup-del admins
+""")
+
+register = Registry()
+
+NETGROUP_PATTERN='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]*$'
+NETGROUP_PATTERN_ERRMSG='may only include letters, numbers, _, -, and .'
+
+# according to most common use cases the netgroup pattern should fit
+# also the nisdomain pattern
+NISDOMAIN_PATTERN=NETGROUP_PATTERN
+NISDOMAIN_PATTERN_ERRMSG=NETGROUP_PATTERN_ERRMSG
+
+output_params = (
+ Str('memberuser_user?',
+ label='Member User',
+ ),
+ Str('memberuser_group?',
+ label='Member Group',
+ ),
+ Str('memberhost_host?',
+ label=_('Member Host'),
+ ),
+ Str('memberhost_hostgroup?',
+ label='Member Hostgroup',
+ ),
+ )
+
+
+@register()
+class netgroup(LDAPObject):
+ """
+ Netgroup object.
+ """
+ container_dn = api.env.container_netgroup
+ object_name = _('netgroup')
+ object_name_plural = _('netgroups')
+ object_class = ['ipaobject', 'ipaassociation', 'ipanisnetgroup']
+ permission_filter_objectclasses = ['ipanisnetgroup']
+ search_attributes = [
+ 'cn', 'description', 'memberof', 'externalhost', 'nisdomainname',
+ 'memberuser', 'memberhost', 'member', 'usercategory', 'hostcategory',
+ ]
+ default_attributes = [
+ 'cn', 'description', 'memberof', 'externalhost', 'nisdomainname',
+ 'memberuser', 'memberhost', 'member', 'memberindirect',
+ 'usercategory', 'hostcategory',
+ ]
+ uuid_attribute = 'ipauniqueid'
+ rdn_attribute = 'ipauniqueid'
+ attribute_members = {
+ 'member': ['netgroup'],
+ 'memberof': ['netgroup'],
+ 'memberindirect': ['netgroup'],
+ 'memberuser': ['user', 'group'],
+ 'memberhost': ['host', 'hostgroup'],
+ }
+ relationships = {
+ 'member': ('Member', '', 'no_'),
+ 'memberof': ('Member Of', 'in_', 'not_in_'),
+ 'memberindirect': (
+ 'Indirect Member', None, 'no_indirect_'
+ ),
+ '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', 'objectclass',
+ },
+ },
+ 'System: Read Netgroup Membership': {
+ 'replaces_global_anonymous_aci': True,
+ 'ipapermbindruletype': 'all',
+ 'ipapermright': {'read', 'search', 'compare'},
+ 'ipapermdefaultattr': {
+ 'externalhost', 'member', 'memberof', 'memberuser',
+ 'memberhost', 'objectclass',
+ },
+ },
+ 'System: Add Netgroups': {
+ 'ipapermright': {'add'},
+ 'replaces': [
+ '(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0;acl "permission:Add netgroups";allow (add) groupdn = "ldap:///cn=Add netgroups,cn=permissions,cn=pbac,$SUFFIX";)',
+ ],
+ 'default_privileges': {'Netgroups Administrators'},
+ },
+ 'System: Modify Netgroup Membership': {
+ 'ipapermright': {'write'},
+ 'ipapermdefaultattr': {
+ 'externalhost', 'member', 'memberhost', 'memberuser'
+ },
+ 'replaces': [
+ '(targetattr = "memberhost || externalhost || memberuser || member")(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0;acl "permission:Modify netgroup membership";allow (write) groupdn = "ldap:///cn=Modify netgroup membership,cn=permissions,cn=pbac,$SUFFIX";)',
+ ],
+ 'default_privileges': {'Netgroups Administrators'},
+ },
+ 'System: Modify Netgroups': {
+ 'ipapermright': {'write'},
+ 'ipapermdefaultattr': {'description'},
+ 'replaces': [
+ '(targetattr = "description")(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0; acl "permission:Modify netgroups";allow (write) groupdn = "ldap:///cn=Modify netgroups,cn=permissions,cn=pbac,$SUFFIX";)',
+ ],
+ 'default_privileges': {'Netgroups Administrators'},
+ },
+ 'System: Remove Netgroups': {
+ 'ipapermright': {'delete'},
+ 'replaces': [
+ '(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0;acl "permission:Remove netgroups";allow (delete) groupdn = "ldap:///cn=Remove netgroups,cn=permissions,cn=pbac,$SUFFIX";)',
+ ],
+ 'default_privileges': {'Netgroups Administrators'},
+ },
+ 'System: Read Netgroup Compat Tree': {
+ 'non_object': True,
+ 'ipapermbindruletype': 'anonymous',
+ 'ipapermlocation': api.env.basedn,
+ 'ipapermtarget': DN('cn=ng', 'cn=compat', api.env.basedn),
+ 'ipapermright': {'read', 'search', 'compare'},
+ 'ipapermdefaultattr': {
+ 'objectclass', 'cn', 'membernisnetgroup', 'nisnetgrouptriple',
+ },
+ },
+ }
+
+ label = _('Netgroups')
+ label_singular = _('Netgroup')
+
+ takes_params = (
+ Str('cn',
+ pattern=NETGROUP_PATTERN,
+ pattern_errmsg=NETGROUP_PATTERN_ERRMSG,
+ cli_name='name',
+ label=_('Netgroup name'),
+ primary_key=True,
+ normalizer=lambda value: value.lower(),
+ ),
+ Str('description?',
+ cli_name='desc',
+ label=_('Description'),
+ doc=_('Netgroup description'),
+ ),
+ Str('nisdomainname?',
+ pattern=NISDOMAIN_PATTERN,
+ pattern_errmsg=NISDOMAIN_PATTERN_ERRMSG,
+ cli_name='nisdomain',
+ label=_('NIS domain name'),
+ ),
+ Str('ipauniqueid?',
+ cli_name='uuid',
+ label='IPA unique ID',
+ doc=_('IPA unique ID'),
+ flags=['no_create', 'no_update'],
+ ),
+ StrEnum('usercategory?',
+ cli_name='usercat',
+ label=_('User category'),
+ doc=_('User category the rule applies to'),
+ values=(u'all', ),
+ ),
+ StrEnum('hostcategory?',
+ cli_name='hostcat',
+ label=_('Host category'),
+ doc=_('Host category the rule applies to'),
+ values=(u'all', ),
+ ),
+ external_host_param,
+ )
+
+
+@register()
+class netgroup_add(LDAPCreate):
+ __doc__ = _('Add a new netgroup.')
+
+ has_output_params = LDAPCreate.has_output_params + output_params
+ msg_summary = _('Added netgroup "%(value)s"')
+
+ msg_collision = _(u'hostgroup with name "%s" already exists. ' \
+ u'Hostgroups and netgroups share a common namespace')
+
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
+ entry_attrs.setdefault('nisdomainname', self.api.env.domain)
+
+ try:
+ test_dn = self.obj.get_dn(keys[-1])
+ netgroup = ldap.get_entry(test_dn, ['objectclass'])
+ if 'mepManagedEntry' in netgroup.get('objectclass', []):
+ raise errors.DuplicateEntry(message=unicode(self.msg_collision % keys[-1]))
+ else:
+ self.obj.handle_duplicate_entry(*keys)
+ except errors.NotFound:
+ pass
+
+ try:
+ # when enabled, a managed netgroup is created for every hostgroup
+ # make sure that we don't create a collision if the plugin is
+ # (temporarily) disabled
+ api.Object['hostgroup'].get_dn_if_exists(keys[-1])
+ raise errors.DuplicateEntry(message=unicode(self.msg_collision % keys[-1]))
+ except errors.NotFound:
+ pass
+
+ return dn
+
+
+@register()
+class netgroup_del(LDAPDelete):
+ __doc__ = _('Delete a netgroup.')
+
+ msg_summary = _('Deleted netgroup "%(value)s"')
+
+
+
+@register()
+class netgroup_mod(LDAPUpdate):
+ __doc__ = _('Modify a netgroup.')
+
+ has_output_params = LDAPUpdate.has_output_params + output_params
+ msg_summary = _('Modified netgroup "%(value)s"')
+
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
+ try:
+ entry_attrs = ldap.get_entry(dn, attrs_list)
+ dn = entry_attrs.dn
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+ if is_all(options, 'usercategory') and 'memberuser' in entry_attrs:
+ raise errors.MutuallyExclusiveError(reason=_("user category cannot be set to 'all' while there are allowed users"))
+ if is_all(options, 'hostcategory') and 'memberhost' in entry_attrs:
+ raise errors.MutuallyExclusiveError(reason=_("host category cannot be set to 'all' while there are allowed hosts"))
+ return dn
+
+
+@register()
+class netgroup_find(LDAPSearch):
+ __doc__ = _('Search for a netgroup.')
+
+ member_attributes = ['member', 'memberuser', 'memberhost', 'memberof']
+ has_output_params = LDAPSearch.has_output_params + output_params
+ msg_summary = ngettext(
+ '%(count)d netgroup matched', '%(count)d netgroups matched', 0
+ )
+
+ takes_options = LDAPSearch.takes_options + (
+ Flag('private',
+ exclude='webui',
+ flags=['no_option', 'no_output'],
+ ),
+ Flag('managed',
+ cli_name='managed',
+ doc=_('search for managed groups'),
+ default_from=lambda private: private,
+ ),
+ )
+
+ def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
+ # Do not display private mepManagedEntry netgroups by default
+ # If looking for managed groups, we need to omit the negation search filter
+
+ search_kw = {}
+ search_kw['objectclass'] = ['mepManagedEntry']
+ if not options['managed']:
+ local_filter = ldap.make_filter(search_kw, rules=ldap.MATCH_NONE)
+ else:
+ local_filter = ldap.make_filter(search_kw, rules=ldap.MATCH_ALL)
+ filter = ldap.combine_filters((local_filter, filter), rules=ldap.MATCH_ALL)
+ return (filter, base_dn, scope)
+
+
+@register()
+class netgroup_show(LDAPRetrieve):
+ __doc__ = _('Display information about a netgroup.')
+
+ has_output_params = LDAPRetrieve.has_output_params + output_params
+
+
+@register()
+class netgroup_add_member(LDAPAddMember):
+ __doc__ = _('Add members to a netgroup.')
+
+ member_attributes = ['memberuser', 'memberhost', 'member']
+ has_output_params = LDAPAddMember.has_output_params + output_params
+
+ def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
+ return add_external_pre_callback('host', ldap, dn, keys, options)
+
+ def post_callback(self, ldap, completed, failed, dn, entry_attrs,
+ *keys, **options):
+ assert isinstance(dn, DN)
+ return add_external_post_callback(ldap, dn, entry_attrs,
+ failed=failed,
+ completed=completed,
+ memberattr='memberhost',
+ membertype='host',
+ externalattr='externalhost')
+
+
+@register()
+class netgroup_remove_member(LDAPRemoveMember):
+ __doc__ = _('Remove members from a netgroup.')
+
+ member_attributes = ['memberuser', 'memberhost', 'member']
+ has_output_params = LDAPRemoveMember.has_output_params + output_params
+
+ def post_callback(self, ldap, completed, failed, dn, entry_attrs,
+ *keys, **options):
+ assert isinstance(dn, DN)
+ return remove_external_post_callback(ldap, dn, entry_attrs,
+ failed=failed,
+ completed=completed,
+ memberattr='memberhost',
+ membertype='host',
+ externalattr='externalhost')