Global trust configuration is generated ipa-adtrust-install script is run. Add convenience commands to show auto-generated options like SID or GUID or options chosen by user (NetBIOS). Most of these options are not modifiable via trustconfig-mod command as it would break current trusts.
Unit test file covering these new commands was added. https://fedorahosted.org/freeipa/ticket/3333
From 091e7436201b012a12578dea20175750f3a80956 Mon Sep 17 00:00:00 2001 From: Martin Kosek <[email protected]> Date: Fri, 25 Jan 2013 10:10:17 +0100 Subject: [PATCH] Add trusconfig-show and trustconfig-mod commands Global trust configuration is generated ipa-adtrust-install script is run. Add convenience commands to show auto-generated options like SID or GUID or options chosen by user (NetBIOS). Most of these options are not modifiable via trustconfig-mod command as it would break current trusts. Unit test file covering these new commands was added. https://fedorahosted.org/freeipa/ticket/3333 --- ipalib/plugins/trust.py | 172 +++++++++++++++++++++++++++++++++ tests/test_xmlrpc/test_trust_plugin.py | 159 ++++++++++++++++++++++++++++++ tests/test_xmlrpc/xmlrpc_test.py | 10 ++ 3 files changed, 341 insertions(+) create mode 100644 tests/test_xmlrpc/test_trust_plugin.py diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py index 2019d910b18ea507b9d05f5b6165e7b6d9a43e4e..8bcb0548e294e97283c9407c2b85356a3d118625 100644 --- a/ipalib/plugins/trust.py +++ b/ipalib/plugins/trust.py @@ -1,5 +1,6 @@ # Authors: # Alexander Bokovoy <[email protected]> +# Martin Kosek <[email protected]> # # Copyright (C) 2011 Red Hat # see file 'COPYING' for use and warranty information @@ -95,6 +96,22 @@ Example: 4. List members of external members of ad_admins_external group to see their SIDs: ipa group-show ad_admins_external + + +GLOBAL TRUST CONFIGURATION + +When IPA AD trust subpackage is installed and ipa-adtrust-install is run, +a local domain configuration (SID, GUID, NetBIOS name) is generated. These +identifiers are then used when communicating with a trusted domain of the +particular type. + +1. Show global trust configuration for Active Directory type of trust + + ipa trustconfig-show --type ad + +2. Modify global trust configuration and set different primary fallback group + + ipa trustconfig-mod --type ad --fallback-primary-group "alternative AD group" """) trust_output_params = ( @@ -482,3 +499,158 @@ api.register(trust_mod) api.register(trust_del) api.register(trust_find) api.register(trust_show) + + +_trust_type_option = ( + StrEnum('trust_type', + cli_name='type', + label=_('Trust type (ad for Active Directory, default)'), + values=(u'ad',), + default=u'ad', + autofill=True, + ), +) + +class trustconfig(LDAPObject): + """ + Trusts global configuration object + """ + object_name = _('trust configuration') + default_attributes = [ + 'cn', 'ipantsecurityidentifier', 'ipantflatname', 'ipantdomainguid', + 'ipantfallbackprimarygroup', + ] + + label = _('Global Trust Configuration') + label_singular = _('Global Trust Configuration') + + takes_params = ( + Str('cn', + label=_('Domain'), + flags=['no_update'], + ), + Str('ipantsecurityidentifier', + label=_('Security Identifier'), + flags=['no_update'], + ), + Str('ipantflatname', + label=_('NetBIOS name'), + flags=['no_update'], + ), + Str('ipantdomainguid', + label=_('Domain GUID'), + flags=['no_update'], + ), + Str('ipantfallbackprimarygroup', + cli_name='fallback_primary_group', + label=_('Fallback primary group'), + ), + ) + + def get_dn(self, *keys, **kwargs): + trust_type = kwargs.get('trust_type') + if trust_type is None: + raise errors.RequirementError(name='trust_type') + if kwargs['trust_type'] == u'ad': + return DN(('cn', self.api.env.domain), + self.api.env.container_cifsdomains, self.api.env.basedn) + raise errors.ValidationError(name='trust_type', + error=_("unsupported trust type")) + + def _normalize_groupdn(self, entry_attrs): + """ + Checks that group with given name/DN exists and updates the entry_attrs + """ + if 'ipantfallbackprimarygroup' not in entry_attrs: + return + + group = entry_attrs['ipantfallbackprimarygroup'] + if isinstance(group, (list, tuple)): + group = group[0] + + if group is None: + return + + try: + dn = DN(group) + # group is in a form of a DN + try: + self.backend.get_entry(dn) + except errors.NotFound: + self.api.Object['group'].handle_not_found(group) + # DN is valid, we can just return + return + except ValueError: + # The search is performed for groups with "posixgroup" objectclass + # and not "ipausergroup" so that it can also match groups like + # "Default SMG Group" which does not have this objectclass. + try: + (dn, group_entry) = self.backend.find_entry_by_attr( + self.api.Object['group'].primary_key.name, + group, + ['posixgroup'], + [''], + self.api.Object['group'].container_dn) + except errors.NotFound: + self.api.Object['group'].handle_not_found(group) + else: + entry_attrs['ipantfallbackprimarygroup'] = [dn] + + def _convert_groupdn(self, entry_attrs, options): + """ + Convert an group dn into a name. As we use CN as user RDN, its value + can be extraceted from the DN without further LDAP queries. + """ + if options.get('raw', False): + return + + try: + groupdn = entry_attrs['ipantfallbackprimarygroup'][0] + except (IndexError, KeyError): + groupdn = None + + if groupdn is None: + return + assert isinstance(groupdn, DN) + + entry_attrs['ipantfallbackprimarygroup'] = [groupdn[0][0].value] + +api.register(trustconfig) + +class trustconfig_mod(LDAPUpdate): + __doc__ = _('Modify global trust configuration.') + + takes_options = LDAPUpdate.takes_options + _trust_type_option + msg_summary = _('Modified "%(value)s" trust configuration') + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): + self.obj._normalize_groupdn(entry_attrs) + return dn + + def execute(self, *keys, **options): + result = super(trustconfig_mod, self).execute(*keys, **options) + result['value'] = options['trust_type'] + return result + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + self.obj._convert_groupdn(entry_attrs, options) + return dn + +api.register(trustconfig_mod) + + +class trustconfig_show(LDAPRetrieve): + __doc__ = _('Show global trust configuration.') + + takes_options = LDAPRetrieve.takes_options + _trust_type_option + + def execute(self, *keys, **options): + result = super(trustconfig_show, self).execute(*keys, **options) + result['value'] = options['trust_type'] + return result + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + self.obj._convert_groupdn(entry_attrs, options) + return dn + +api.register(trustconfig_show) diff --git a/tests/test_xmlrpc/test_trust_plugin.py b/tests/test_xmlrpc/test_trust_plugin.py new file mode 100644 index 0000000000000000000000000000000000000000..7627be748137be181ce561aa774a1258b0ba253f --- /dev/null +++ b/tests/test_xmlrpc/test_trust_plugin.py @@ -0,0 +1,159 @@ +# Authors: +# Martin Kosek <[email protected]> +# +# Copyright (C) 2010 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/>. +""" +Test the `ipalib/plugins/trust.py` module. +""" + +import nose +from ipalib import api, errors +from ipapython.dn import DN +from tests.test_xmlrpc import objectclasses +from xmlrpc_test import (Declarative, fuzzy_guid, fuzzy_domain_sid, fuzzy_string, + fuzzy_uuid, fuzzy_digits) + + +trustconfig_ad_config = DN(('cn', api.env.domain), + api.env.container_cifsdomains, api.env.basedn) +testgroup = u'adtestgroup' +testgroup_dn = DN(('cn', testgroup), api.env.container_group, api.env.basedn) + +default_group = u'Default SMB Group' +default_group_dn = DN(('cn', default_group), api.env.container_group, api.env.basedn) + +class test_trustconfig(Declarative): + + @classmethod + def setUpClass(cls): + super(test_trustconfig, cls).setUpClass() + if not api.Backend.xmlclient.isconnected(): + api.Backend.xmlclient.connect(fallback=False) + try: + api.Command['trustconfig_show'](trust_type=u'ad') + except errors.NotFound: + raise nose.SkipTest('Trusts are not configured') + + cleanup_commands = [ + ('group_del', [testgroup], {}), + ('trustconfig_mod', [], {'trust_type': u'ad', + 'ipantfallbackprimarygroup': default_group}), + ] + + tests = [ + + dict( + desc='Retrieve trust configuration for AD domains', + command=('trustconfig_show', [], {'trust_type': u'ad'}), + expected={ + 'value': u'ad', + 'summary': None, + 'result': { + 'dn': trustconfig_ad_config, + 'cn': [api.env.domain], + 'ipantdomainguid': [fuzzy_guid], + 'ipantfallbackprimarygroup': [default_group], + 'ipantflatname': [fuzzy_string], + 'ipantsecurityidentifier': [fuzzy_domain_sid] + }, + }, + ), + + dict( + desc='Retrieve trust configuration for AD domains with --raw', + command=('trustconfig_show', [], {'trust_type': u'ad', 'raw': True}), + expected={ + 'value': u'ad', + 'summary': None, + 'result': { + 'dn': trustconfig_ad_config, + 'cn': [api.env.domain], + 'ipantdomainguid': [fuzzy_guid], + 'ipantfallbackprimarygroup': [default_group_dn], + 'ipantflatname': [fuzzy_string], + 'ipantsecurityidentifier': [fuzzy_domain_sid] + }, + }, + ), + + dict( + desc='Create auxiliary group %r' % testgroup, + command=( + 'group_add', [testgroup], dict(description=u'Test group') + ), + expected=dict( + value=testgroup, + summary=u'Added group "%s"' % testgroup, + result=dict( + cn=[testgroup], + description=[u'Test group'], + gidnumber=[fuzzy_digits], + objectclass=objectclasses.group + [u'posixgroup'], + ipauniqueid=[fuzzy_uuid], + dn=testgroup_dn, + ), + ), + ), + + dict( + desc='Try to change primary fallback group to nonexistent group', + command=('trustconfig_mod', [], + {'trust_type': u'ad', 'ipantfallbackprimarygroup': u'doesnotexist'}), + expected=errors.NotFound(reason=u'%s: group not found' % 'doesnotexist') + ), + + dict( + desc='Try to change primary fallback group to nonexistent group DN', + command=('trustconfig_mod', [], {'trust_type': u'ad', + 'ipantfallbackprimarygroup': u'cn=doesnotexist,dc=test'}), + expected=errors.NotFound(reason=u'%s: group not found' % 'cn=doesnotexist,dc=test') + ), + + dict( + desc='Change primary fallback group to "%s"' % testgroup, + command=('trustconfig_mod', [], {'trust_type': u'ad', + 'ipantfallbackprimarygroup': testgroup}), + expected={ + 'value': u'ad', + 'summary': u'Modified "ad" trust configuration', + 'result': { + 'cn': [api.env.domain], + 'ipantdomainguid': [fuzzy_guid], + 'ipantfallbackprimarygroup': [testgroup], + 'ipantflatname': [fuzzy_string], + 'ipantsecurityidentifier': [fuzzy_domain_sid] + }, + }, + ), + + dict( + desc='Change primary fallback group back to "%s" using DN' % default_group, + command=('trustconfig_mod', [], {'trust_type': u'ad', + 'ipantfallbackprimarygroup': unicode(default_group_dn)}), + expected={ + 'value': u'ad', + 'summary': u'Modified "ad" trust configuration', + 'result': { + 'cn': [api.env.domain], + 'ipantdomainguid': [fuzzy_guid], + 'ipantfallbackprimarygroup': [default_group], + 'ipantflatname': [fuzzy_string], + 'ipantsecurityidentifier': [fuzzy_domain_sid] + }, + }, + ), + ] diff --git a/tests/test_xmlrpc/xmlrpc_test.py b/tests/test_xmlrpc/xmlrpc_test.py index 7c32be0db31d69373f988a2bb1ec7171679b36ae..610fa97c56639331c542c9f0d1da8be839a11a2c 100644 --- a/tests/test_xmlrpc/xmlrpc_test.py +++ b/tests/test_xmlrpc/xmlrpc_test.py @@ -40,6 +40,16 @@ fuzzy_uuid = Fuzzy( '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' ) +# Matches trusted domain GUID, like u'463bf2be-3456-4a57-979e-120304f2a0eb' +fuzzy_guid = fuzzy_uuid + +# Matches SID of a trusted domain +# SID syntax: http://msdn.microsoft.com/en-us/library/ff632068.aspx +_sid_identifier_authority = '(0x[0-9a-f]{1,12}|[0-9]{1,10})' +fuzzy_domain_sid = Fuzzy( + '^S-1-5-21-%(idauth)s-%(idauth)s-%(idauth)s$' % dict(idauth=_sid_identifier_authority) +) + # Matches netgroup dn. Note (?i) at the beginning of the regexp is the ingnore case flag fuzzy_netgroupdn = Fuzzy( '(?i)ipauniqueid=[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12},cn=ng,cn=alt,%s' % api.env.basedn -- 1.7.11.7
_______________________________________________ Freeipa-devel mailing list [email protected] https://www.redhat.com/mailman/listinfo/freeipa-devel
