1 # Copyright (C) 2014 Ipsilon project Contributors, for license see COPYING
9 from ipsilon.helpers.common import EnvHelpersInstaller
12 IPA_CONFIG_FILE = '/etc/ipa/default.conf'
13 HTTPD_IPA_KEYTAB = '/etc/httpd/conf/ipa.keytab'
14 IPA_COMMAND = '/usr/bin/ipa'
15 IPA_GETKEYTAB = '/usr/sbin/ipa-getkeytab'
18 NO_CREDS_FOR_KEYTAB = """
19 Valid IPA admin credentials are required to get a keytab.
20 Please kinit with a pivileged user like 'admin' and retry.
23 FAILED_TO_GET_KEYTAB = """
24 A pre-existing keytab was not found and it was not possible to
25 successfully retrieve a new keytab for the IPA server. Please
26 manually provide a keytab or resolve the error that cause this
27 failure (see logs) and retry.
31 class Installer(EnvHelpersInstaller):
33 def __init__(self, *pargs):
34 super(Installer, self).__init__()
42 def install_args(self, group):
43 group.add_argument('--ipa', choices=['yes', 'no', 'auto'],
45 help='Helper for IPA joined machines')
47 def conf_init(self, opts):
49 # Do a simple check to see if machine is ipa joined
50 if not os.path.exists(IPA_CONFIG_FILE):
51 logger.info('No IPA configuration file. Skipping ipa helper...')
52 if opts['ipa'] == 'yes':
53 raise Exception('No IPA installation found!')
56 # Get config vars from ipa file
58 from ipapython import config as ipaconfig
60 ipaconfig.init_config()
61 self.realm = ipaconfig.config.get_realm()
62 self.domain = ipaconfig.config.get_domain()
63 self.server = ipaconfig.config.get_server()
65 except Exception, e: # pylint: disable=broad-except
66 logger.info('IPA tools installation found: [%s]', e)
67 if opts['ipa'] == 'yes':
68 raise Exception('No IPA installation found!')
71 def get_keytab(self, opts):
73 # Check if we have need ipa tools
74 if not os.path.exists(IPA_GETKEYTAB):
75 logger.info('ipa-getkeytab missing. Will skip keytab creation.')
76 if opts['ipa'] == 'yes':
77 raise Exception('No IPA tools found!')
79 # Check if we already have a keytab for HTTP
80 if 'gssapi_httpd_keytab' in opts:
81 msg = "Searching for keytab in: %s" % opts['gssapi_httpd_keytab']
82 if os.path.exists(opts['gssapi_httpd_keytab']):
83 logger.info(msg + "... Found!")
86 logger.info(msg + "... Not found!")
88 msg = "Searching for keytab in: %s" % HTTPD_IPA_KEYTAB
89 if os.path.exists(HTTPD_IPA_KEYTAB):
90 opts['gssapi_httpd_keytab'] = HTTPD_IPA_KEYTAB
91 logger.info(msg + "... Found!")
94 logger.info(msg + "... Not found!")
96 us = socket.gethostname()
97 princ = 'HTTP/%s@%s' % (us, self.realm)
99 # Check we have credentials to access server (for keytab)
100 from ipalib import api
101 from ipalib import errors as ipaerrors
103 api.bootstrap(context='ipsilon_installer')
107 api.Backend.rpcclient.connect()
108 logger.debug('Try RPC connection')
109 api.Backend.rpcclient.forward('ping')
110 logger.debug("... Succeeded!")
111 except ipaerrors.KerberosError as e:
112 logger.error('Invalid credentials: [%s]', repr(e))
113 if api.Backend.rpcclient.isconnected():
114 api.Backend.rpcclient.disconnect()
115 raise Exception('Invalid credentials: [%s]' % e)
116 except ipaerrors.PublicError as e:
118 'Cannot connect to the server due to generic error: %s', e)
119 if api.Backend.rpcclient.isconnected():
120 api.Backend.rpcclient.disconnect()
121 raise Exception('Unable to connect to IPA server: %s' % e)
123 # Specify an older version to work on nearly any master. Force is
124 # set to True so a DNS A record is not required for adding the
127 api.Backend.rpcclient.forward(
133 except ipaerrors.DuplicateEntry:
134 logger.debug('Principal %s already exists', princ)
135 except ipaerrors.NotFound as e:
136 logger.error('%s', e)
137 raise Exception('%s' % e)
138 except ipaerrors.ACIError as e:
139 logger.error(NO_CREDS_FOR_KEYTAB)
140 logger.debug('Invalid credentials: [%s]', repr(e))
141 raise Exception('Invalid credentials: [%s]' % e)
143 server = api.Backend.rpcclient.api.env.server
144 if api.Backend.rpcclient.isconnected():
145 api.Backend.rpcclient.disconnect()
148 msg = "Trying to fetch keytab[%s] for %s" % (
149 opts['gssapi_httpd_keytab'], princ)
151 subprocess.check_output([IPA_GETKEYTAB,
152 '-s', server, '-p', princ,
153 '-k', opts['gssapi_httpd_keytab']],
154 stderr=subprocess.STDOUT)
155 except subprocess.CalledProcessError, e:
156 # unfortunately this one is fatal
157 logger.error(FAILED_TO_GET_KEYTAB)
158 logger.info('Error trying to get HTTP keytab:')
159 logger.info('Cmd> %s\n%s', e.cmd, e.output)
160 raise Exception('Missing keytab: [%s]' % e)
162 # Fixup permissions so only the ipsilon user can read these files
163 pw = pwd.getpwnam(HTTPD_USER)
164 os.chown(opts['gssapi_httpd_keytab'], pw.pw_uid, pw.pw_gid)
166 def configure_server(self, opts):
167 if opts['ipa'] != 'yes' and opts['ipa'] != 'auto':
169 if opts['ipa'] != 'yes' and opts['gssapi'] == 'no':
172 self.logger = logging.getLogger()
176 self.get_keytab(opts)
178 # Forcibly use gssapi then pam modules
179 if 'lm_order' not in opts:
180 opts['lm_order'] = []
181 opts['gssapi'] = 'yes'
182 if 'gssapi' not in opts['lm_order']:
183 opts['lm_order'].insert(0, 'gssapi')
185 if not any(lm in opts['lm_order'] for lm in ('form', 'pam')):
186 opts['lm_order'].append('form')