#308 Replace ipalib with ipa command line
Closed 2 years ago by puiterwijk. Opened 2 years ago by cheimes.
cheimes/ipsilon ipa_cli  into  master

@@ -21,7 +21,6 @@ 

  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

file modified
+35 -69
@@ -35,9 +35,6 @@ 

          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 @@ 

                  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 @@ 

              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)

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 cheimes@redhat.com

rebased onto d3f0aeb9a176216875aa9602d2aca8f5d540d057

2 years ago

I have successfully tested the patch with a client machine on freeipa-client-4.7.0-1.fc28.x86_64 against a server a server with FreeIPA 4.6.4.

1 new commit added

  • Remove duplicate BuildArch entry
2 years ago

Jenkins is failing because pylint-2 is missing

rebased onto 51e5a63

2 years ago

@puiterwijk any chance this could be merged?

This looks nice, +1 for merge

Pull-Request has been closed by puiterwijk

2 years ago