|
|
86baa9 |
From 12a079a0b599cf192c4bee8bcc37f1824f82539e Mon Sep 17 00:00:00 2001
|
|
|
86baa9 |
From: Alexander Bokovoy <abokovoy@redhat.com>
|
|
|
86baa9 |
Date: Sun, 31 Mar 2019 10:39:05 +0300
|
|
|
86baa9 |
Subject: [PATCH] oddjob: allow to pass options to trust-fetch-domains
|
|
|
86baa9 |
|
|
|
86baa9 |
Refactor com.redhat.idm.trust-fetch.domains oddjob helper to allow
|
|
|
86baa9 |
passing administrative credentials and a domain controller to talk to.
|
|
|
86baa9 |
|
|
|
86baa9 |
This approach allows to avoid rediscovering a domain controller in case
|
|
|
86baa9 |
a user actually specified the domain controller when establishing trust.
|
|
|
86baa9 |
|
|
|
86baa9 |
It also allows to pass through admin credentials if user decides to do
|
|
|
86baa9 |
so. The latter will be used later to allow updating trust topology in a
|
|
|
86baa9 |
similar oddjob helper.
|
|
|
86baa9 |
|
|
|
86baa9 |
Resolves: https://pagure.io/freeipa/issue/7895
|
|
|
86baa9 |
Reviewed-By: Christian Heimes <cheimes@redhat.com>
|
|
|
86baa9 |
(cherry picked from commit de4a9875d410c68ae4f9602b70c753a11034b31b)
|
|
|
86baa9 |
---
|
|
|
86baa9 |
API.txt | 4 +-
|
|
|
86baa9 |
VERSION.m4 | 4 +-
|
|
|
86baa9 |
.../oddjob/com.redhat.idm.trust-fetch-domains | 91 +++++++++++--------
|
|
|
86baa9 |
.../etc/oddjobd.conf.d/oddjobd-ipa-trust.conf | 2 +-
|
|
|
86baa9 |
ipaserver/plugins/trust.py | 31 ++++++-
|
|
|
86baa9 |
5 files changed, 83 insertions(+), 49 deletions(-)
|
|
|
86baa9 |
|
|
|
86baa9 |
diff --git a/API.txt b/API.txt
|
|
|
86baa9 |
index 222e30915ccc1fb4a6f3ce228669453f346fdde4..325df7a6ef48afbc438bcc1f7b8ca64efb229886 100644
|
|
|
86baa9 |
--- a/API.txt
|
|
|
86baa9 |
+++ b/API.txt
|
|
|
86baa9 |
@@ -5765,10 +5765,12 @@ output: Output('result', type=[<type 'dict'>])
|
|
|
86baa9 |
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
|
|
86baa9 |
output: ListOfPrimaryKeys('value')
|
|
|
86baa9 |
command: trust_fetch_domains/1
|
|
|
86baa9 |
-args: 1,5,4
|
|
|
86baa9 |
+args: 1,7,4
|
|
|
86baa9 |
arg: Str('cn', cli_name='realm')
|
|
|
86baa9 |
option: Flag('all', autofill=True, cli_name='all', default=False)
|
|
|
86baa9 |
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
|
|
86baa9 |
+option: Str('realm_admin?', cli_name='admin')
|
|
|
86baa9 |
+option: Password('realm_passwd?', cli_name='password', confirm=False)
|
|
|
86baa9 |
option: Str('realm_server?', cli_name='server')
|
|
|
86baa9 |
option: Flag('rights', autofill=True, default=False)
|
|
|
86baa9 |
option: Str('version?')
|
|
|
86baa9 |
diff --git a/VERSION.m4 b/VERSION.m4
|
|
|
86baa9 |
index b1425626ca00ffbcc902c66685cb27cbb2136539..da391d8bd4dad6ae8e7418e6af54a9d481133cc8 100644
|
|
|
86baa9 |
--- a/VERSION.m4
|
|
|
86baa9 |
+++ b/VERSION.m4
|
|
|
86baa9 |
@@ -82,8 +82,8 @@ define(IPA_DATA_VERSION, 20100614120000)
|
|
|
86baa9 |
# #
|
|
|
86baa9 |
########################################################
|
|
|
86baa9 |
define(IPA_API_VERSION_MAJOR, 2)
|
|
|
86baa9 |
-define(IPA_API_VERSION_MINOR, 230)
|
|
|
86baa9 |
-# Last change: Added `automember-find-orphans' command
|
|
|
86baa9 |
+define(IPA_API_VERSION_MINOR, 231)
|
|
|
86baa9 |
+# Last change: Added admin creds to trust-fetch-domains
|
|
|
86baa9 |
|
|
|
86baa9 |
|
|
|
86baa9 |
########################################################
|
|
|
86baa9 |
diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains
|
|
|
86baa9 |
index 30150793d98011d153081477c0856618e1454ba5..1e90759e0e6e7be36745ec12f4478bfec0f0358e 100755
|
|
|
86baa9 |
--- a/install/oddjob/com.redhat.idm.trust-fetch-domains
|
|
|
86baa9 |
+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains
|
|
|
86baa9 |
@@ -14,11 +14,31 @@ import pwd
|
|
|
86baa9 |
import six
|
|
|
86baa9 |
import gssapi
|
|
|
86baa9 |
|
|
|
86baa9 |
-from ipalib.install.kinit import kinit_keytab
|
|
|
86baa9 |
+from ipalib.install.kinit import kinit_keytab, kinit_password
|
|
|
86baa9 |
|
|
|
86baa9 |
if six.PY3:
|
|
|
86baa9 |
unicode = str
|
|
|
86baa9 |
|
|
|
86baa9 |
+
|
|
|
86baa9 |
+def parse_options():
|
|
|
86baa9 |
+ usage = "%prog <trusted domain name>\n"
|
|
|
86baa9 |
+ parser = config.IPAOptionParser(usage=usage,
|
|
|
86baa9 |
+ formatter=config.IPAFormatter())
|
|
|
86baa9 |
+
|
|
|
86baa9 |
+ parser.add_option("-d", "--debug", action="store_true", dest="debug",
|
|
|
86baa9 |
+ help="Display debugging information")
|
|
|
86baa9 |
+ parser.add_option("-s", "--server", action="store", dest="server",
|
|
|
86baa9 |
+ help="Domain controller for the Active Directory domain (optional)")
|
|
|
86baa9 |
+ parser.add_option("-a", "--admin", action="store", dest="admin",
|
|
|
86baa9 |
+ help="Active Directory administrator (optional)")
|
|
|
86baa9 |
+ parser.add_option("-p", "--password", action="store", dest="password",
|
|
|
86baa9 |
+ help="Display debugging information")
|
|
|
86baa9 |
+
|
|
|
86baa9 |
+ options, args = parser.parse_args()
|
|
|
86baa9 |
+ safe_options = parser.get_safe_opts(options)
|
|
|
86baa9 |
+
|
|
|
86baa9 |
+ return safe_options, options, args
|
|
|
86baa9 |
+
|
|
|
86baa9 |
def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal):
|
|
|
86baa9 |
getkeytab_args = ["/usr/sbin/ipa-getkeytab",
|
|
|
86baa9 |
"-s", api.env.host,
|
|
|
86baa9 |
@@ -40,7 +60,7 @@ def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal):
|
|
|
86baa9 |
pass
|
|
|
86baa9 |
|
|
|
86baa9 |
|
|
|
86baa9 |
-def get_forest_root_domain(api_instance, trusted_domain):
|
|
|
86baa9 |
+def get_forest_root_domain(api_instance, trusted_domain, server=None):
|
|
|
86baa9 |
"""
|
|
|
86baa9 |
retrieve trusted forest root domain for given domain name
|
|
|
86baa9 |
|
|
|
86baa9 |
@@ -53,25 +73,11 @@ def get_forest_root_domain(api_instance, trusted_domain):
|
|
|
86baa9 |
flatname = trustconfig_show()['result']['ipantflatname'][0]
|
|
|
86baa9 |
|
|
|
86baa9 |
remote_domain = dcerpc.retrieve_remote_domain(
|
|
|
86baa9 |
- api_instance.env.host, flatname, trusted_domain)
|
|
|
86baa9 |
+ api_instance.env.host, flatname, trusted_domain,
|
|
|
86baa9 |
+ realm_server=server)
|
|
|
86baa9 |
|
|
|
86baa9 |
return remote_domain.info['dns_forest']
|
|
|
86baa9 |
|
|
|
86baa9 |
-
|
|
|
86baa9 |
-def parse_options():
|
|
|
86baa9 |
- usage = "%prog <trusted domain name>\n"
|
|
|
86baa9 |
- parser = config.IPAOptionParser(usage=usage,
|
|
|
86baa9 |
- formatter=config.IPAFormatter())
|
|
|
86baa9 |
-
|
|
|
86baa9 |
- parser.add_option("-d", "--debug", action="store_true", dest="debug",
|
|
|
86baa9 |
- help="Display debugging information")
|
|
|
86baa9 |
-
|
|
|
86baa9 |
- options, args = parser.parse_args()
|
|
|
86baa9 |
- safe_options = parser.get_safe_opts(options)
|
|
|
86baa9 |
-
|
|
|
86baa9 |
- return safe_options, options, args
|
|
|
86baa9 |
-
|
|
|
86baa9 |
-
|
|
|
86baa9 |
if not is_ipa_configured():
|
|
|
86baa9 |
# LSB status code 6: program is not configured
|
|
|
86baa9 |
raise ScriptError("IPA is not configured " +
|
|
|
86baa9 |
@@ -153,32 +159,37 @@ trusted_domain = trusted_domain_entry.single_value.get('cn').lower()
|
|
|
86baa9 |
# At this point if we didn't find trusted forest name, an exception will be raised
|
|
|
86baa9 |
# and script will quit. This is actually intended.
|
|
|
86baa9 |
|
|
|
86baa9 |
-oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab'
|
|
|
86baa9 |
-oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper()))
|
|
|
86baa9 |
+if not (options.admin and options.password):
|
|
|
86baa9 |
+ oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab'
|
|
|
86baa9 |
+ oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper()))
|
|
|
86baa9 |
|
|
|
86baa9 |
-# If keytab does not exist, retrieve it
|
|
|
86baa9 |
-if not os.path.isfile(oneway_keytab_name):
|
|
|
86baa9 |
- retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
|
|
|
86baa9 |
+ # If keytab does not exist, retrieve it
|
|
|
86baa9 |
+ if not os.path.isfile(oneway_keytab_name):
|
|
|
86baa9 |
+ retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
|
|
|
86baa9 |
|
|
|
86baa9 |
-try:
|
|
|
86baa9 |
- have_ccache = False
|
|
|
86baa9 |
try:
|
|
|
86baa9 |
- # The keytab may have stale key material (from older trust-add run)
|
|
|
86baa9 |
- cred = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
|
|
|
86baa9 |
- if cred.lifetime > 0:
|
|
|
86baa9 |
- have_ccache = True
|
|
|
86baa9 |
- except gssapi.exceptions.ExpiredCredentialsError:
|
|
|
86baa9 |
- pass
|
|
|
86baa9 |
- if not have_ccache:
|
|
|
86baa9 |
+ have_ccache = False
|
|
|
86baa9 |
+ try:
|
|
|
86baa9 |
+ # The keytab may have stale key material (from older trust-add run)
|
|
|
86baa9 |
+ cred = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
|
|
|
86baa9 |
+ if cred.lifetime > 0:
|
|
|
86baa9 |
+ have_ccache = True
|
|
|
86baa9 |
+ except gssapi.exceptions.ExpiredCredentialsError:
|
|
|
86baa9 |
+ pass
|
|
|
86baa9 |
+ if not have_ccache:
|
|
|
86baa9 |
+ if os.path.exists(oneway_ccache_name):
|
|
|
86baa9 |
+ os.unlink(oneway_ccache_name)
|
|
|
86baa9 |
+ kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
|
|
|
86baa9 |
+ except gssapi.exceptions.GSSError:
|
|
|
86baa9 |
+ # If there was failure on using keytab, assume it is stale and retrieve again
|
|
|
86baa9 |
+ retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
|
|
|
86baa9 |
if os.path.exists(oneway_ccache_name):
|
|
|
86baa9 |
os.unlink(oneway_ccache_name)
|
|
|
86baa9 |
kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
|
|
|
86baa9 |
-except gssapi.exceptions.GSSError:
|
|
|
86baa9 |
- # If there was failure on using keytab, assume it is stale and retrieve again
|
|
|
86baa9 |
- retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
|
|
|
86baa9 |
- if os.path.exists(oneway_ccache_name):
|
|
|
86baa9 |
- os.unlink(oneway_ccache_name)
|
|
|
86baa9 |
- kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
|
|
|
86baa9 |
+else:
|
|
|
86baa9 |
+ cred = kinit_password(options.admin, options.password,
|
|
|
86baa9 |
+ oneway_ccache_name,
|
|
|
86baa9 |
+ canonicalize=True, enterprise=True)
|
|
|
86baa9 |
|
|
|
86baa9 |
# We are done: we have ccache with TDO credentials and can fetch domains
|
|
|
86baa9 |
ipa_domain = api.env.domain
|
|
|
86baa9 |
@@ -186,9 +197,9 @@ os.environ['KRB5CCNAME'] = oneway_ccache_name
|
|
|
86baa9 |
|
|
|
86baa9 |
# retrieve the forest root domain name and contact it to retrieve trust
|
|
|
86baa9 |
# topology info
|
|
|
86baa9 |
-forest_root = get_forest_root_domain(api, trusted_domain)
|
|
|
86baa9 |
+forest_root = get_forest_root_domain(api, trusted_domain, server=options.server)
|
|
|
86baa9 |
|
|
|
86baa9 |
-domains = dcerpc.fetch_domains(api, ipa_domain, forest_root, creds=True)
|
|
|
86baa9 |
+domains = dcerpc.fetch_domains(api, ipa_domain, forest_root, creds=True, server=options.server)
|
|
|
86baa9 |
trust_domain_object = api.Command.trust_show(trusted_domain, raw=True)['result']
|
|
|
86baa9 |
trust.add_new_domains_from_trust(api, None, trust_domain_object, domains)
|
|
|
86baa9 |
|
|
|
86baa9 |
diff --git a/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf b/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf
|
|
|
86baa9 |
index 630a4e6cd4c0d3ed9ce48bf9b882b7d630f6bbf3..9f3f168a51abfdd1cb7cb8b76221bb4ec806859c 100644
|
|
|
86baa9 |
--- a/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf
|
|
|
86baa9 |
+++ b/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf
|
|
|
86baa9 |
@@ -11,7 +11,7 @@
|
|
|
86baa9 |
<interface name="com.redhat.idm.trust">
|
|
|
86baa9 |
<method name="fetch_domains">
|
|
|
86baa9 |
|
|
|
86baa9 |
- arguments="1"
|
|
|
86baa9 |
+ arguments="30"
|
|
|
86baa9 |
argument_passing_method="cmdline"
|
|
|
86baa9 |
prepend_user_name="no"/>
|
|
|
86baa9 |
</method>
|
|
|
86baa9 |
diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py
|
|
|
86baa9 |
index 91cd1387ce058f34c2319676767d9e50f9b46ed1..bb9e0fe3303989c49cf339df6e5aeeb4ce1435cf 100644
|
|
|
86baa9 |
--- a/ipaserver/plugins/trust.py
|
|
|
86baa9 |
+++ b/ipaserver/plugins/trust.py
|
|
|
86baa9 |
@@ -418,9 +418,19 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options):
|
|
|
86baa9 |
return range_type, range_size, base_id
|
|
|
86baa9 |
|
|
|
86baa9 |
|
|
|
86baa9 |
-def fetch_trusted_domains_over_dbus(myapi, forest_name):
|
|
|
86baa9 |
+def fetch_trusted_domains_over_dbus(myapi, *keys, **options):
|
|
|
86baa9 |
if not _bindings_installed:
|
|
|
86baa9 |
return
|
|
|
86baa9 |
+
|
|
|
86baa9 |
+ forest_name = keys[0]
|
|
|
86baa9 |
+ method_options = []
|
|
|
86baa9 |
+ if 'realm_server' in options:
|
|
|
86baa9 |
+ method_options.extend(['--server', options['realm_server']])
|
|
|
86baa9 |
+ if 'realm_admin' in options:
|
|
|
86baa9 |
+ method_options.extend(['--admin', options['realm_admin']])
|
|
|
86baa9 |
+ if 'realm_passwd' in options:
|
|
|
86baa9 |
+ method_options.extend(['--password', options['realm_passwd']])
|
|
|
86baa9 |
+
|
|
|
86baa9 |
# Calling oddjobd-activated service via DBus has some quirks:
|
|
|
86baa9 |
# - Oddjobd registers multiple canonical names on the same address
|
|
|
86baa9 |
# - python-dbus only follows name owner changes when mainloop is in use
|
|
|
86baa9 |
@@ -436,7 +446,8 @@ def fetch_trusted_domains_over_dbus(myapi, forest_name):
|
|
|
86baa9 |
fetch_domains_method = intf.get_dbus_method(
|
|
|
86baa9 |
'fetch_domains',
|
|
|
86baa9 |
dbus_interface=DBUS_IFACE_TRUST)
|
|
|
86baa9 |
- (_ret, _stdout, _stderr) = fetch_domains_method(forest_name)
|
|
|
86baa9 |
+ (_ret, _stdout, _stderr) = fetch_domains_method(
|
|
|
86baa9 |
+ [forest_name] + method_options)
|
|
|
86baa9 |
except dbus.DBusException as e:
|
|
|
86baa9 |
logger.error('Failed to call %s.fetch_domains helper.'
|
|
|
86baa9 |
'DBus exception is %s.', DBUS_IFACE_TRUST, str(e))
|
|
|
86baa9 |
@@ -1760,10 +1771,20 @@ class trust_fetch_domains(LDAPRetrieve):
|
|
|
86baa9 |
|
|
|
86baa9 |
has_output = output.standard_list_of_entries
|
|
|
86baa9 |
takes_options = LDAPRetrieve.takes_options + (
|
|
|
86baa9 |
+ Str('realm_admin?',
|
|
|
86baa9 |
+ cli_name='admin',
|
|
|
86baa9 |
+ label=_("Active Directory domain administrator"),
|
|
|
86baa9 |
+ ),
|
|
|
86baa9 |
+ Password('realm_passwd?',
|
|
|
86baa9 |
+ cli_name='password',
|
|
|
86baa9 |
+ label=_("Active Directory domain administrator's password"),
|
|
|
86baa9 |
+ confirm=False,
|
|
|
86baa9 |
+ ),
|
|
|
86baa9 |
Str('realm_server?',
|
|
|
86baa9 |
cli_name='server',
|
|
|
86baa9 |
- label=_('Domain controller for the Active Directory domain (optional)'),
|
|
|
86baa9 |
- ),
|
|
|
86baa9 |
+ label=_('Domain controller for the Active Directory domain '
|
|
|
86baa9 |
+ '(optional)'),
|
|
|
86baa9 |
+ ),
|
|
|
86baa9 |
)
|
|
|
86baa9 |
|
|
|
86baa9 |
def execute(self, *keys, **options):
|
|
|
86baa9 |
@@ -1784,7 +1805,7 @@ class trust_fetch_domains(LDAPRetrieve):
|
|
|
86baa9 |
# With privilege separation we also cannot authenticate as
|
|
|
86baa9 |
# HTTP/ principal because we have no access to its key material.
|
|
|
86baa9 |
# Thus, we'll use DBus call out to oddjobd helper in all cases
|
|
|
86baa9 |
- fetch_trusted_domains_over_dbus(self.api, keys[0])
|
|
|
86baa9 |
+ fetch_trusted_domains_over_dbus(self.api, *keys, **options)
|
|
|
86baa9 |
result['summary'] = unicode(_('List of trust domains successfully '
|
|
|
86baa9 |
'refreshed. Use trustdomain-find '
|
|
|
86baa9 |
'command to list them.'))
|
|
|
86baa9 |
--
|
|
|
86baa9 |
2.20.1
|
|
|
86baa9 |
|