From 51e5a633c9262176b2ea68e4c83ff5959dfbb43f Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sep 06 2018 09:34:30 +0000 Subject: [PATCH 1/2] Replace ipalib with ipa command line Ipsilion uses ipalib just to parse FreeIPA's config file and to create a service principal. This can be easily archived by shelling out to the ipa command line tool. The server, realm, and domain names are not required either. * Use subprocess.check_output() * ipa-getkeytab no longer needs '-s server' argument. It can parse /etc/ipa/default.conf on its own. * The service principal name doesn't need the @REALM suffix. FreeIPA adds it automatically. The change is necessary, because FreeIPA 4.8 will drop support for Python 2 and Ipsilon is still not fully ported to Python 3. See: https://fedoraproject.org/wiki/Changes/FreeIPA_Python_2_Removal Signed-off-by: Christian Heimes --- diff --git a/ipsilon/helpers/ipa.py b/ipsilon/helpers/ipa.py index 8111eb8..c14a9ea 100644 --- a/ipsilon/helpers/ipa.py +++ b/ipsilon/helpers/ipa.py @@ -35,9 +35,6 @@ class Installer(EnvHelpersInstaller): self.name = 'ipa' self.ptype = 'helper' self.logger = None - self.realm = None - self.domain = None - self.server = None def install_args(self, group): group.add_argument('--ipa', choices=['yes', 'no', 'auto'], @@ -53,20 +50,13 @@ class Installer(EnvHelpersInstaller): raise Exception('No IPA installation found!') return - # Get config vars from ipa file - try: - from ipapython import config as ipaconfig - - ipaconfig.init_config() - self.realm = ipaconfig.config.get_realm() - self.domain = ipaconfig.config.get_domain() - self.server = ipaconfig.config.get_server() - - except Exception as e: # pylint: disable=broad-except - logger.info('IPA tools installation found: [%s]', e) - if opts['ipa'] == 'yes': - raise Exception('No IPA installation found!') - return + def _check_output(self, args, **kwargs): + env = os.environ.copy() + # enforce English to disable i18n + env['LC_ALL'] = env['LANG'] = 'en_US.utf8' + return subprocess.check_output( + args, env=env, stderr=subprocess.STDOUT, **kwargs + ) def get_keytab(self, opts): logger = self.logger @@ -94,72 +84,48 @@ class Installer(EnvHelpersInstaller): logger.info(msg + "... Not found!") us = socket.gethostname() - princ = 'HTTP/%s@%s' % (us, self.realm) + princ = 'HTTP/%s' % us # Check we have credentials to access server (for keytab) - from ipalib import api - from ipalib import errors as ipaerrors - - api.bootstrap(context='ipsilon_installer') - api.finalize() - try: - api.Backend.rpcclient.connect() - logger.debug('Try RPC connection') - api.Backend.rpcclient.forward('ping') - logger.debug("... Succeeded!") - except ipaerrors.KerberosError as e: - logger.error('Invalid credentials: [%s]', repr(e)) - if api.Backend.rpcclient.isconnected(): - api.Backend.rpcclient.disconnect() - raise Exception('Invalid credentials: [%s]' % e) - except ipaerrors.PublicError as e: - logger.error( - 'Cannot connect to the server due to generic error: %s', e) - if api.Backend.rpcclient.isconnected(): - api.Backend.rpcclient.disconnect() + logger.debug('Try to ping IPA server') + self._check_output([IPA_COMMAND, 'ping']) + except subprocess.CalledProcessError as e: + logger.error('Cannot connect to server: %s', e) raise Exception('Unable to connect to IPA server: %s' % e) + else: + logger.debug("... Succeeded!") - # Specify an older version to work on nearly any master. Force is - # set to True so a DNS A record is not required for adding the - # service. + # Force is set to True so a DNS A record is not required for + # adding the service. try: - api.Backend.rpcclient.forward( - 'service_add', - unicode(princ), - force=True, - version=u'2.0', + self._check_output( + [IPA_COMMAND, 'service-add', princ, '--force'] ) - except ipaerrors.DuplicateEntry: - logger.debug('Principal %s already exists', princ) - except ipaerrors.NotFound as e: - logger.error('%s', e) - raise Exception('%s' % e) - except ipaerrors.ACIError as e: - logger.error(NO_CREDS_FOR_KEYTAB) - logger.debug('Invalid credentials: [%s]', repr(e)) - raise Exception('Invalid credentials: [%s]' % e) - finally: - server = api.Backend.rpcclient.api.env.server - if api.Backend.rpcclient.isconnected(): - api.Backend.rpcclient.disconnect() + except subprocess.CalledProcessError as e: + if 'already exists' in e.output: + logger.debug('Principal %s already exists', princ) + else: + logger.error('%s', e) + raise Exception(e.output) msg = "Trying to fetch keytab[%s] for %s" % ( opts['gssapi_httpd_keytab'], princ) logger.info(msg) - gktcmd = [IPA_GETKEYTAB, '-s', server, '-p', princ, '-k', - opts['gssapi_httpd_keytab']] - proc = subprocess.Popen(gktcmd, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - output, dummy_err = proc.communicate() - retcode = proc.poll() - if retcode: + gktcmd = [ + IPA_GETKEYTAB, '-p', princ, '-k', opts['gssapi_httpd_keytab'] + ] + try: + self._check_output(gktcmd) + except subprocess.CalledProcessError as e: # unfortunately this one is fatal logger.error(FAILED_TO_GET_KEYTAB) logger.info('Error trying to get HTTP keytab:') - logger.info('Cmd> %s\n%s', gktcmd, output) - raise Exception('Missing keytab: [Command \'%s\' returned non-zero' - ' exit status %d]' % (gktcmd, retcode)) + logger.info('Cmd> %s\n%s', gktcmd, e.output) + raise Exception( + 'Missing keytab: [Command \'%s\' returned non-zero' + ' exit status %d]' % (gktcmd, e.returncode) + ) # Fixup permissions so only the ipsilon user can read these files pw = pwd.getpwnam(HTTPD_USER) From b539339bd4758b15dd6d8edb0fcc8170e4c0e36b Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sep 06 2018 09:34:32 +0000 Subject: [PATCH 2/2] Remove duplicate BuildArch entry Signed-off-by: Christian Heimes --- diff --git a/contrib/fedora/ipsilon.spec b/contrib/fedora/ipsilon.spec index d4ce8c1..cb6f82f 100644 --- a/contrib/fedora/ipsilon.spec +++ b/contrib/fedora/ipsilon.spec @@ -21,7 +21,6 @@ BuildRequires: m2crypto Requires: python-setuptools Requires: python-requests Requires: %{name}-base = %{version}-%{release} -BuildArch: noarch %description Ipsilon is a multi-protocol Identity Provider service. Its function is to