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