Implement change registration
[cascardo/ipsilon.git] / ipsilon / helpers / ipa.py
old mode 100755 (executable)
new mode 100644 (file)
index 4a4849a..9c786f9
@@ -1,28 +1,12 @@
-#!/usr/bin/python
-#
-# Copyright (C) 2014  Simo Sorce <simo@redhat.com>
-#
-# 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/>.
+# Copyright (C) 2014 Ipsilon project Contributors, for license see COPYING
 
 import logging
 import pwd
 import os
 import socket
 import subprocess
-import sys
+
+from ipsilon.helpers.common import EnvHelpersInstaller
 
 
 IPA_CONFIG_FILE = '/etc/ipa/default.conf'
@@ -44,9 +28,10 @@ failure (see logs) and retry.
 """
 
 
-class Installer(object):
+class Installer(EnvHelpersInstaller):
 
-    def __init__(self):
+    def __init__(self, *pargs):
+        super(Installer, self).__init__()
         self.name = 'ipa'
         self.ptype = 'helper'
         self.logger = None
@@ -78,7 +63,7 @@ class Installer(object):
             self.server = ipaconfig.config.get_server()
 
         except Exception, e:  # pylint: disable=broad-except
-            logger.info('IPA tools installation found: [%s]', str(e))
+            logger.info('IPA tools installation found: [%s]', e)
             if opts['ipa'] == 'yes':
                 raise Exception('No IPA installation found!')
             return
@@ -92,83 +77,96 @@ class Installer(object):
                 raise Exception('No IPA tools found!')
 
         # Check if we already have a keytab for HTTP
-        if 'krb_httpd_keytab' in opts:
-            msg = "Searching for keytab in: %s" % opts['krb_httpd_keytab']
-            print >> sys.stdout, msg,
-            if os.path.exists(opts['krb_httpd_keytab']):
-                print >> sys.stdout, "... Found!"
+        if 'gssapi_httpd_keytab' in opts:
+            msg = "Searching for keytab in: %s" % opts['gssapi_httpd_keytab']
+            if os.path.exists(opts['gssapi_httpd_keytab']):
+                logger.info(msg + "... Found!")
                 return
             else:
-                print >> sys.stdout, "... Not found!"
+                logger.info(msg + "... Not found!")
 
         msg = "Searching for keytab in: %s" % HTTPD_IPA_KEYTAB
-        print >> sys.stdout, msg,
         if os.path.exists(HTTPD_IPA_KEYTAB):
-            opts['krb_httpd_keytab'] = HTTPD_IPA_KEYTAB
-            print >> sys.stdout, "... Found!"
+            opts['gssapi_httpd_keytab'] = HTTPD_IPA_KEYTAB
+            logger.info(msg + "... Found!")
             return
         else:
-            print >> sys.stdout, "... Not found!"
+            logger.info(msg + "... Not found!")
 
         us = socket.gethostname()
         princ = 'HTTP/%s@%s' % (us, self.realm)
 
         # Check we have credentials to access server (for keytab)
-        from ipapython import ipaldap
+        from ipalib import api
         from ipalib import errors as ipaerrors
 
-        for srv in self.server:
-            msg = "Testing access to server: %s" % srv
-            print >> sys.stdout, msg,
-            try:
-                server = srv
-                c = ipaldap.IPAdmin(host=server)
-                c.do_sasl_gssapi_bind()
-                del c
-                print >> sys.stdout, "... Succeeded!"
-                break
-            except ipaerrors.ACIError, e:
-                # usually this error is returned when we have no
-                # good credentials, ask the user to kinit and retry
-                print >> sys.stderr, NO_CREDS_FOR_KEYTAB
-                logger.error('Invalid credentials: [%s]', repr(e))
-                raise Exception('Invalid credentials: [%s]', str(e))
-            except Exception, e:  # pylint: disable=broad-except
-                # for other exceptions let's try to fail later
-                pass
+        api.bootstrap(context='ipsilon_installer')
+        api.finalize()
 
         try:
-            subprocess.check_output([IPA_COMMAND, 'service-add', princ],
-                                    stderr=subprocess.STDOUT)
-        except subprocess.CalledProcessError, e:
-            # hopefully this means the service already exists
-            # otherwise we'll fail later again
-            logger.info('Error trying to create HTTP service:')
-            logger.info('Cmd> %s\n%s', e.cmd, e.output)
+            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()
+            raise Exception('Unable to connect to IPA server: %s' % e)
+
+        # 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.
+        try:
+            api.Backend.rpcclient.forward(
+                'service_add',
+                unicode(princ),
+                force=True,
+                version=u'2.0',
+            )
+        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()
 
         try:
             msg = "Trying to fetch keytab[%s] for %s" % (
-                  opts['krb_httpd_keytab'], princ)
-            print >> sys.stdout, msg,
+                  opts['gssapi_httpd_keytab'], princ)
+            logger.info(msg)
             subprocess.check_output([IPA_GETKEYTAB,
                                      '-s', server, '-p', princ,
-                                     '-k', opts['krb_httpd_keytab']],
+                                     '-k', opts['gssapi_httpd_keytab']],
                                     stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError, e:
             # unfortunately this one is fatal
-            print >> sys.stderr, FAILED_TO_GET_KEYTAB
+            logger.error(FAILED_TO_GET_KEYTAB)
             logger.info('Error trying to get HTTP keytab:')
             logger.info('Cmd> %s\n%s', e.cmd, e.output)
-            raise Exception('Missing keytab: [%s]' % str(e))
+            raise Exception('Missing keytab: [%s]' % e)
 
         # Fixup permissions so only the ipsilon user can read these files
         pw = pwd.getpwnam(HTTPD_USER)
-        os.chown(opts['krb_httpd_keytab'], pw.pw_uid, pw.pw_gid)
+        os.chown(opts['gssapi_httpd_keytab'], pw.pw_uid, pw.pw_gid)
 
-    def configure_server(self, opts):
+    def configure_server(self, opts, changes):
         if opts['ipa'] != 'yes' and opts['ipa'] != 'auto':
             return
-        if opts['ipa'] != 'yes' and opts['krb'] == 'no':
+        if opts['ipa'] != 'yes' and opts['gssapi'] == 'no':
             return
 
         self.logger = logging.getLogger()
@@ -177,12 +175,12 @@ class Installer(object):
 
         self.get_keytab(opts)
 
-        # Forcibly use krb then pam modules
+        # Forcibly use gssapi then pam modules
         if 'lm_order' not in opts:
             opts['lm_order'] = []
-        opts['krb'] = 'yes'
-        if 'krb' not in opts['lm_order']:
-            opts['lm_order'].insert(0, 'krb')
+        opts['gssapi'] = 'yes'
+        if 'gssapi' not in opts['lm_order']:
+            opts['lm_order'].insert(0, 'gssapi')
         opts['form'] = 'yes'
         if not any(lm in opts['lm_order'] for lm in ('form', 'pam')):
             opts['lm_order'].append('form')