diff options
-rw-r--r-- | contrib/fedora/ipsilon.spec | 1 | ||||
-rwxr-xr-x | ipsilon/helpers/ipa.py | 170 | ||||
-rwxr-xr-x | setup.py | 2 |
3 files changed, 172 insertions, 1 deletions
diff --git a/contrib/fedora/ipsilon.spec b/contrib/fedora/ipsilon.spec index f86e4de..f5e1931 100644 --- a/contrib/fedora/ipsilon.spec +++ b/contrib/fedora/ipsilon.spec @@ -98,6 +98,7 @@ semanage fcontext -d -t httpd_var_lib_t '%{_sharedstatedir}/ipsilon(/.*)?' 2>/de %{python2_sitelib}/ipsilon-*.egg-info %{python2_sitelib}/ipsilon/__init__.py* %{python2_sitelib}/ipsilon/tools/* +%{python2_sitelib}/ipsilon/helpers/* %{_datadir}/ipsilon/templates/install/saml2/sp.conf %{_datadir}/ipsilon/ui/saml2sp/* %{_bindir}/ipsilon-client-install diff --git a/ipsilon/helpers/ipa.py b/ipsilon/helpers/ipa.py new file mode 100755 index 0000000..df6717f --- /dev/null +++ b/ipsilon/helpers/ipa.py @@ -0,0 +1,170 @@ +#!/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/>. + +import logging +import pwd +import os +import socket +import subprocess +import sys + + +IPA_CONFIG_FILE = '/etc/ipa/default.conf' +HTTPD_IPA_KEYTAB = '/etc/httpd/conf/ipa.keytab' +IPA_COMMAND = '/usr/bin/ipa' +IPA_GETKEYTAB = '/usr/sbin/ipa-getkeytab' +HTTPD_USER = 'apache' + +NO_CREDS_FOR_KEYTAB = """ +Valid IPA admin credentials are required to get a keytab. +Please kinit with a pivileged user like 'admin' and retry. +""" + +FAILED_TO_GET_KEYTAB = """ +A pre-existing keytab was not found and it was not possible to +successfully retrieve a new keytab for the IPA server. Please +manually provide a keytab or resolve the error that cause this +failure (see logs) and retry. +""" + + +class Installer(object): + + def __init__(self): + 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'], + default='auto', + help='Helper for IPA joined machines') + + def conf_init(self, opts): + logger = self.logger + # Do a simple check to see if machine is ipa joined + if not os.path.exists(IPA_CONFIG_FILE): + logger.info('No IPA configuration file. Skipping ipa helper...') + if opts['ipa'] == 'yes': + 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, e: # pylint: disable=broad-except + logger.info('IPA tools installation found: [%s]', str(e)) + if opts['ipa'] == 'yes': + raise Exception('No IPA installation found!') + return + + def get_keytab(self, opts): + logger = self.logger + # Check if we have need ipa tools + if not os.path.exists(IPA_GETKEYTAB): + logger.info('ipa-getkeytab missing. Will skip keytab creation.') + if opts['ipa'] == 'yes': + raise Exception('No IPA tools found!') + + # Check if we already have a keytab for HTTP + if 'krb_httpd_keytab' in opts: + if os.path.exists(opts['krb_httpd_keytab']): + return + + if os.path.exists(HTTPD_IPA_KEYTAB): + opts['krb_httpd_keytab'] = HTTPD_IPA_KEYTAB + return + + 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 errors as ipaerrors + + for srv in self.server: + try: + server = srv + c = ipaldap.IPAdmin(host=server) + c.do_sasl_gssapi_bind() + del c + 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 + + 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) + + try: + subprocess.check_output([IPA_GETKEYTAB, + '-s', server, '-p', princ, + '-k', opts['krb_httpd_keytab']], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError, e: + # unfortunately this one is fatal + print >> sys.stderr, 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)) + + # 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) + + def configure_server(self, opts): + if opts['ipa'] != 'yes' and opts['ipa'] != 'auto': + return + + self.logger = logging.getLogger() + + self.conf_init(opts) + + self.get_keytab(opts) + + # Forcibly use krb then pam modules + if not 'lm_order' in opts: + opts['lm_order'] = [] + opts['krb'] = 'yes' + if 'krb' not in opts['lm_order']: + opts['lm_order'].insert(0, 'krb') + opts['pam'] = 'yes' + if 'pam' not in opts['lm_order']: + opts['lm_order'].append('pam') @@ -28,7 +28,7 @@ setup( license = 'GPLv3+', packages = ['ipsilon', 'ipsilon.admin', 'ipsilon.login', 'ipsilon.util', 'ipsilon.providers', 'ipsilon.providers.saml2', - 'ipsilon.tools'], + 'ipsilon.tools', 'ipsilon.helpers'], data_files = [('share/man/man7', ["man/ipsilon.7"]), ('share/doc/ipsilon', ['COPYING']), ('share/doc/ipsilon/examples', ['examples/ipsilon.conf', |