Improve compatibility with IPA v4.5.0+

The changes were more significant than just a few imports as
initially thought. The RPC API changed signficantly mostly due
to switching from NSS to OpenSSL as the crypto layer.

Related changes include:

* Handling the new random password generator
* Writing the CA chain to a file instead of an NSS db
* Dealing with certificates having their own object

These are handled via the ipapython.version library to tell
what version of IPA we have. This cannot rely on the API
value because these changes are lower-level.

Change-Id: I8ee03edc4b0b2db566db43f2ea64256fe15a3a8b
This commit is contained in:
Rob Crittenden 2017-09-06 16:43:14 -04:00
parent 038e17027d
commit 5ab8dac221
2 changed files with 66 additions and 10 deletions

View File

@ -34,6 +34,7 @@ from ipapython.ipautil import realm_to_suffix
from ipapython.ipautil import run
from ipapython.ipautil import user_input
from ipapython.ipautil import write_tmp_file
from ipapython import version
from novajoin.errors import ConfigurationError
try:
@ -48,6 +49,9 @@ except ImportError:
# The import moved in freeIPA 4.5.0
from ipalib.install.kinit import kinit_password
if version.NUM_VERSION >= 40500:
from cryptography.hazmat.primitives import serialization
import nss.nss as nss
logger = logging.getLogger()
@ -135,12 +139,21 @@ class NovajoinRole(object):
def _get_ca_certs(self, server, realm):
basedn = realm_to_suffix(realm)
try:
conn = ipaldap.IPAdmin(server, sasl_nocanon=True)
conn.do_sasl_gssapi_bind()
certs = certstore.get_ca_certs(conn, basedn, realm, False)
except Exception as e:
raise ConfigurationError("get_ca_certs_from_ldap() error: %s" % e)
if version.NUM_VERSION >= 40500:
ldap_uri = ipaldap.get_ldap_uri(server)
try:
conn = ipaldap.LDAPClient(ldap_uri, sasl_nocanon=True)
conn.gssapi_bind()
certs = certstore.get_ca_certs(conn, basedn, realm, False)
except Exception as e:
raise ConfigurationError("get_ca_certs() error: %s" % e)
else:
try:
conn = ipaldap.IPAdmin(server, sasl_nocanon=True)
conn.do_sasl_gssapi_bind()
certs = certstore.get_ca_certs(conn, basedn, realm, False)
except Exception as e:
raise ConfigurationError("get_ca_certs() error: %s" % e)
certs = [x509.load_certificate(c[0], x509.DER) for c in certs
if c[2] is not False]
@ -148,6 +161,13 @@ class NovajoinRole(object):
return certs
def create_nssdb(self, server, realm):
"""Retrieve IPA CA certificate chain to NSS database.
Retrieve the CA cert chain from IPA and add it to a
temporary NSS database and return the path to it.
NOTE: For IPA v4.4.0.
"""
nss.nss_init_nodb()
nss_db = certdb.NSSDatabase()
@ -166,6 +186,26 @@ class NovajoinRole(object):
return nss_db
def create_cafile(self, server, realm):
"""Retrieve IPA CA certificate chain to a file
Retrieve the CA cert chain from IPA and add it to a
temporary file and return the name of the file.
The caller is responsible for removing the temporary file.
NOTE: For IPA v4.5.0+
"""
(cafile_fd, cafile_name) = tempfile.mkstemp()
os.close(cafile_fd)
ca_certs = self._get_ca_certs(server, realm)
ca_certs = [cert.public_bytes(serialization.Encoding.PEM)
for cert in ca_certs]
x509.write_certificate_list(ca_certs, cafile_name)
return cafile_name
def kinit(self, principal, realm, password, config=None):
ccache_dir = tempfile.mkdtemp(prefix='krbcc')
self.ccache_name = os.path.join(ccache_dir, 'ccache')
@ -262,7 +302,10 @@ class NovajoinRole(object):
def _add_host(self, filename):
logging.debug('Add host %s', self.hostname)
otp = ipa_generate_password(allowed_chars)
if version.NUM_VERSION >= 40500:
otp = ipa_generate_password(special=None)
else:
otp = ipa_generate_password(allowed_chars)
self._call_ipa(u'host_add', six.text_type(self.hostname),
{'description': u'Undercloud host',

View File

@ -19,6 +19,7 @@ import os
import shutil
import sys
from ipalib import api, errors
from ipapython import version
from ipapython.ipa_log_manager import log_mgr
from novajoin import configure_ipa
from novajoin.errors import ConfigurationError
@ -87,16 +88,26 @@ if __name__ == '__main__':
os.remove(krb5_conf)
nss_db = None
cafile = None
if precreate_opts_specified:
nss_db = novajoin.create_nssdb(opts.server, opts.realm)
args['nss_dir'] = unicode(nss_db.secdir)
# IPA v4.5.0 switched client from NSS to OpenSSL
if version.NUM_VERSION >= 40500:
cafile = novajoin.create_cafile(opts.server, opts.realm)
# Workaround for https://pagure.io/freeipa/issue/7145
args['tls_ca_cert'] = cafile.decode('UTF-8')
else:
nss_db = novajoin.create_nssdb(opts.server, opts.realm)
args['nss_dir'] = nss_db.secdir.decode('UTF-8')
api.bootstrap(**args)
api.finalize()
logging.debug('Connect to IPA backend')
try:
if nss_db:
if cafile:
api.Backend.rpcclient.connect(ca_certfile=cafile)
elif nss_db:
api.Backend.rpcclient.connect(nss_dir=nss_db.secdir)
else:
api.Backend.rpcclient.connect()
@ -109,6 +120,8 @@ if __name__ == '__main__':
if nss_db:
nss_db.close()
if cafile:
os.remove(cafile)
if krb5_conf:
os.remove(krb5_conf)
if ccache_dir: