summaryrefslogtreecommitdiffstats
path: root/ipalib/plugins/group.py
diff options
context:
space:
mode:
authorAlexander Bokovoy <abokovoy@redhat.com>2012-06-20 16:08:33 +0300
committerMartin Kosek <mkosek@redhat.com>2012-06-28 16:53:33 +0200
commita6ff85f425d5c38dd89fcd8999e0d62eadb969a1 (patch)
tree04ae9b01be916209b2156e915da7ebddff065fc0 /ipalib/plugins/group.py
parent52f69aaa8ab4d633bbeb96799bf96e8a715d0ae0 (diff)
downloadfreeipa-a6ff85f425d5c38dd89fcd8999e0d62eadb969a1.tar.gz
freeipa-a6ff85f425d5c38dd89fcd8999e0d62eadb969a1.tar.xz
freeipa-a6ff85f425d5c38dd89fcd8999e0d62eadb969a1.zip
Add support for external group members
When using ipaExternalGroup/ipaExternalMember attributes it is possible to add group members which don't exist in IPA database. This is primarily is required for AD trusts support and therefore validation is accepting only secure identifier (SID) format. https://fedorahosted.org/freeipa/ticket/2664
Diffstat (limited to 'ipalib/plugins/group.py')
-rw-r--r--ipalib/plugins/group.py108
1 files changed, 104 insertions, 4 deletions
diff --git a/ipalib/plugins/group.py b/ipalib/plugins/group.py
index 65657363..74bea170 100644
--- a/ipalib/plugins/group.py
+++ b/ipalib/plugins/group.py
@@ -22,6 +22,12 @@ from ipalib import api
from ipalib import Int, Str
from ipalib.plugins.baseldap import *
from ipalib import _, ngettext
+if api.env.in_server and api.env.context in ['lite', 'server']:
+ try:
+ import ipaserver.dcerpc
+ _dcerpc_bindings_installed = True
+ except Exception, e:
+ _dcerpc_bindings_installed = False
__doc__ = _("""
Groups of users
@@ -83,11 +89,11 @@ class group(LDAPObject):
object_name_plural = _('groups')
object_class = ['ipausergroup']
object_class_config = 'ipagroupobjectclasses'
- possible_objectclasses = ['posixGroup', 'mepManagedEntry']
+ possible_objectclasses = ['posixGroup', 'mepManagedEntry', 'ipaExternalGroup']
search_attributes_config = 'ipagroupsearchfields'
default_attributes = [
'cn', 'description', 'gidnumber', 'member', 'memberof',
- 'memberindirect', 'memberofindirect',
+ 'memberindirect', 'memberofindirect', 'ipaexternalmember',
]
uuid_attribute = 'ipauniqueid'
attribute_members = {
@@ -139,10 +145,22 @@ class group_add(LDAPCreate):
doc=_('Create as a non-POSIX group'),
default=False,
),
+ Flag('external',
+ cli_name='external',
+ doc=_('Allow adding external non-IPA members from trusted domains'),
+ default=False,
+ ),
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
- if not options['nonposix']:
+ # As both 'external' and 'nonposix' options have default= set for
+ # them, they will always be present in options dict, thus we can
+ # safely reference the values
+ if options['external']:
+ entry_attrs['objectclass'].append('ipaexternalgroup')
+ if 'gidnumber' in options:
+ raise errors.RequirementError(name='gid')
+ elif not options['nonposix']:
entry_attrs['objectclass'].append('posixgroup')
if not 'gidnumber' in options:
entry_attrs['gidnumber'] = 999
@@ -194,11 +212,18 @@ class group_mod(LDAPUpdate):
cli_name='posix',
doc=_('change to a POSIX group'),
),
+ Flag('external',
+ cli_name='external',
+ doc=_('change to support external non-IPA members from trusted domains'),
+ default=False,
+ ),
)
def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
- if options['posix'] or 'gidnumber' in options:
+ if ('posix' in options and options['posix']) or 'gidnumber' in options:
(dn, old_entry_attrs) = ldap.get_entry(dn, ['objectclass'])
+ if 'ipaexternalgroup' in old_entry_attrs['objectclass']:
+ raise errors.ExternalGroupViolation()
if 'posixgroup' in old_entry_attrs['objectclass']:
if options['posix']:
raise errors.AlreadyPosixGroup()
@@ -207,6 +232,15 @@ class group_mod(LDAPUpdate):
entry_attrs['objectclass'] = old_entry_attrs['objectclass']
if not 'gidnumber' in options:
entry_attrs['gidnumber'] = 999
+ if options['external']:
+ (dn, old_entry_attrs) = ldap.get_entry(dn, ['objectclass'])
+ if 'posixgroup' in old_entry_attrs['objectclass']:
+ raise errors.PosixGroupViolation()
+ if 'ipaexternalgroup' in old_entry_attrs['objectclass']:
+ raise errors.AlreadyExternalGroup()
+ else:
+ old_entry_attrs['objectclass'].append('ipaexternalgroup')
+ entry_attrs['objectclass'] = old_entry_attrs['objectclass']
# Can't check for this in a validator because we lack context
if 'gidnumber' in options and options['gidnumber'] is None:
raise errors.RequirementError(name='gid')
@@ -274,12 +308,64 @@ api.register(group_show)
class group_add_member(LDAPAddMember):
__doc__ = _('Add members to a group.')
+ takes_options = (
+ Str('ipaexternalmember*',
+ cli_name='external',
+ label=_('External member'),
+ doc=_('comma-separated SIDs of members of a trusted domain'),
+ csv=True,
+ flags=['no_create', 'no_update', 'no_search'],
+ ),
+ )
+
+ def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ result = (completed, dn)
+ if 'ipaexternalmember' in options:
+ if not _dcerpc_bindings_installed:
+ raise errors.NotFound(name=_('AD Trust'),
+ reason=_('''Cannot perform external member validation without Samba 4 support installed.
+ Make sure you have installed server-trust-ad sub-package of IPA on the server'''))
+ domain_validator = ipaserver.dcerpc.DomainValidator(self.api)
+ if not domain_validator.is_configured():
+ raise errors.NotFound(name=_('AD Trust setup'),
+ reason=_('''Cannot perform join operation without own domain configured.
+ Make sure you have run ipa-adtrust-install on the IPA server first'''))
+ sids = []
+ failed_sids = []
+ for sid in options['ipaexternalmember']:
+ if domain_validator.is_trusted_sid_valid(sid):
+ sids.append(sid)
+ else:
+ failed_sids.append((sid, 'Not a trusted domain SID'))
+ if len(sids) == 0:
+ raise errors.ValidationError(name=_('external member'),
+ error=_('values are not recognized as valid SIDs from trusted domain'))
+ restore = []
+ if 'member' in failed and 'group' in failed['member']:
+ restore = failed['member']['group']
+ failed['member']['group'] = list((id,id) for id in sids)
+ result = add_external_post_callback('member', 'group', 'ipaexternalmember',
+ ldap, completed, failed, dn, entry_attrs,
+ keys, options, external_callback_normalize=False)
+ failed['member']['group'] = restore + failed_sids
+ return result
+
api.register(group_add_member)
class group_remove_member(LDAPRemoveMember):
__doc__ = _('Remove members from a group.')
+ takes_options = (
+ Str('ipaexternalmember*',
+ cli_name='external',
+ label=_('External member'),
+ doc=_('comma-separated SIDs of members of a trusted domain'),
+ csv=True,
+ flags=['no_create', 'no_update', 'no_search'],
+ ),
+ )
+
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
if keys[0] == protected_group_name:
result = api.Command.group_show(protected_group_name)
@@ -290,6 +376,20 @@ class group_remove_member(LDAPRemoveMember):
label=_(u'group'), container=protected_group_name)
return dn
+ def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ result = (completed, dn)
+ if 'ipaexternalmember' in options:
+ sids = options['ipaexternalmember']
+ restore = list()
+ if 'member' in failed and 'group' in failed['member']:
+ restore = failed['member']['group']
+ failed['member']['group'] = list((id,id) for id in sids)
+ result = remove_external_post_callback('member', 'group', 'ipaexternalmember',
+ ldap, completed, failed, dn, entry_attrs,
+ keys, options)
+ failed['member']['group'] = restore
+ return result
+
api.register(group_remove_member)