mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2026-08-17 16:34:56 -05:00
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
This commit is contained in:
@@ -3262,6 +3262,30 @@ option: Str('version?', exclude='webui')
|
||||
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
||||
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
|
||||
output: Output('value', <type 'unicode'>, None)
|
||||
command: trustconfig_mod
|
||||
args: 0,9,3
|
||||
option: Str('addattr*', cli_name='addattr', exclude='webui')
|
||||
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
|
||||
option: Str('delattr*', cli_name='delattr', exclude='webui')
|
||||
option: Str('ipantfallbackprimarygroup', attribute=True, autofill=False, cli_name='fallback_primary_group', multivalue=False, required=False)
|
||||
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
|
||||
option: Flag('rights', autofill=True, default=False)
|
||||
option: Str('setattr*', cli_name='setattr', exclude='webui')
|
||||
option: StrEnum('trust_type', autofill=True, cli_name='type', default=u'ad', values=(u'ad',))
|
||||
option: Str('version?', exclude='webui')
|
||||
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
||||
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
|
||||
output: Output('value', <type 'unicode'>, None)
|
||||
command: trustconfig_show
|
||||
args: 0,5,3
|
||||
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
|
||||
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
|
||||
option: Flag('rights', autofill=True, default=False)
|
||||
option: StrEnum('trust_type', autofill=True, cli_name='type', default=u'ad', values=(u'ad',))
|
||||
option: Str('version?', exclude='webui')
|
||||
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
||||
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
|
||||
output: Output('value', <type 'unicode'>, None)
|
||||
command: user_add
|
||||
args: 1,34,3
|
||||
arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, required=True)
|
||||
|
||||
@@ -89,4 +89,4 @@ IPA_DATA_VERSION=20100614120000
|
||||
# #
|
||||
########################################################
|
||||
IPA_API_VERSION_MAJOR=2
|
||||
IPA_API_VERSION_MINOR=47
|
||||
IPA_API_VERSION_MINOR=48
|
||||
|
||||
+183
-7
@@ -1,5 +1,6 @@
|
||||
# Authors:
|
||||
# Alexander Bokovoy <abokovoy@redhat.com>
|
||||
# Martin Kosek <mkosek@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2011 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
@@ -95,6 +96,30 @@ 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 trusts:
|
||||
|
||||
ipa trustconfig-show --type ad
|
||||
|
||||
2. Modify global configuration for all trusts of Active Directory type and set
|
||||
a different fallback primary group (fallback primary group GID is used as
|
||||
a primary user GID if user authenticating to IPA domain does not have any other
|
||||
primary GID already set):
|
||||
|
||||
ipa trustconfig-mod --type ad --fallback-primary-group "alternative AD group"
|
||||
|
||||
3. Change primary fallback group back to default hidden group (any group with
|
||||
posixGroup object class is allowed):
|
||||
|
||||
ipa trustconfig-mod --type ad --fallback-primary-group "Default SMB Group"
|
||||
""")
|
||||
|
||||
trust_output_params = (
|
||||
@@ -120,6 +145,14 @@ _trust_status_dict = {True : _('Established and verified'),
|
||||
False : _('Waiting for confirmation by remote side')}
|
||||
_trust_type_dict_unknown = _('Unknown')
|
||||
|
||||
_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,
|
||||
)
|
||||
|
||||
def trust_type_string(level):
|
||||
"""
|
||||
Returns a string representing a type of the trust. The original field is an enum:
|
||||
@@ -193,13 +226,7 @@ sides.
|
||||
''')
|
||||
|
||||
takes_options = LDAPCreate.takes_options + (
|
||||
StrEnum('trust_type',
|
||||
cli_name='type',
|
||||
label=_('Trust type (ad for Active Directory, default)'),
|
||||
values=(u'ad',),
|
||||
default=u'ad',
|
||||
autofill=True,
|
||||
),
|
||||
_trust_type_option,
|
||||
Str('realm_admin?',
|
||||
cli_name='admin',
|
||||
label=_("Active Directory domain administrator"),
|
||||
@@ -482,3 +509,152 @@ api.register(trust_mod)
|
||||
api.register(trust_del)
|
||||
api.register(trust_find)
|
||||
api.register(trust_show)
|
||||
|
||||
_trustconfig_dn = {
|
||||
u'ad': DN(('cn', api.env.domain), api.env.container_cifsdomains, api.env.basedn),
|
||||
}
|
||||
|
||||
|
||||
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')
|
||||
try:
|
||||
return _trustconfig_dn[kwargs['trust_type']]
|
||||
except KeyError:
|
||||
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 SMB 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 extracted 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)
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
# Authors:
|
||||
# Martin Kosek <mkosek@redhat.com>
|
||||
#
|
||||
# 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]
|
||||
},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user