diff options
author | John Dennis <jdennis@redhat.com> | 2012-11-15 14:57:52 -0500 |
---|---|---|
committer | Rob Crittenden <rcritten@redhat.com> | 2013-01-23 14:26:42 -0500 |
commit | a1991aeac19c3fec1fdd0d184c6760c90c9f9fc9 (patch) | |
tree | 1832274281bcb92cd933b2262b2be221efd031f5 /ipa-client/ipaclient | |
parent | 91f4af7e6af53e1c6bf17ed36cb2161863eddae4 (diff) | |
download | freeipa.git-a1991aeac19c3fec1fdd0d184c6760c90c9f9fc9.tar.gz freeipa.git-a1991aeac19c3fec1fdd0d184c6760c90c9f9fc9.tar.xz freeipa.git-a1991aeac19c3fec1fdd0d184c6760c90c9f9fc9.zip |
Use secure method to acquire IPA CA certificate
Major changes ipa-client-install:
* Use GSSAPI connection to LDAP server to download CA cert (now
the default method)
* Add --ca-cert-file option to load the CA cert from a disk file.
Validate the file. If this option is used the supplied CA cert
is considered definitive.
* The insecure HTTP retrieval method is still supported but it must be
explicitly forced and a warning will be emitted.
* Remain backward compatible with unattended case (except for aberrant
condition when preexisting /etc/ipa/ca.crt differs from securely
obtained CA cert, see below)
* If /etc/ipa/ca.crt CA cert preexists the validate it matches the
securely acquired CA cert, if not:
- If --unattended and not --force abort with error
- If interactive query user to accept new CA cert, if not abort
In either case warn user.
* If interactive and LDAP retrieval fails prompt user if they want to
proceed with insecure HTTP method
* If not interactive and LDAP retrieval fails abort unless --force
* Backup preexisting /etc/ipa/ca.crt in FileStore prior to execution,
if ipa-client-install fails it will be restored.
Other changes:
* Add new exception class CertificateInvalidError
* Add utility convert_ldap_error() to ipalib.ipautil
* Replace all hardcoded instances of /etc/ipa/ca.crt in
ipa-client-install with CACERT constant (matches existing practice
elsewhere).
* ipadiscovery no longer retrieves CA cert via HTTP.
* Handle LDAP minssf failures during discovery, treat failure to check
ldap server as a warninbg in absebce of a provided CA certificate via
--ca-cert-file or though existing /etc/ipa/ca.crt file.
Signed-off-by: Simo Sorce <simo@redhat.com>
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Diffstat (limited to 'ipa-client/ipaclient')
-rw-r--r-- | ipa-client/ipaclient/ipadiscovery.py | 50 |
1 files changed, 20 insertions, 30 deletions
diff --git a/ipa-client/ipaclient/ipadiscovery.py b/ipa-client/ipaclient/ipadiscovery.py index 2214a81b..18b77a68 100644 --- a/ipa-client/ipaclient/ipadiscovery.py +++ b/ipa-client/ipaclient/ipadiscovery.py @@ -30,11 +30,14 @@ from ipapython.ipautil import run, CalledProcessError, valid_ip, get_ipa_basedn, realm_to_suffix, format_netloc from ipapython.dn import DN +CACERT = '/etc/ipa/ca.crt' + NOT_FQDN = -1 NO_LDAP_SERVER = -2 REALM_NOT_FOUND = -3 NOT_IPA_SERVER = -4 NO_ACCESS_TO_LDAP = -5 +NO_TLS_LDAP = -6 BAD_HOST_CONFIG = -10 UNKNOWN_ERROR = -15 @@ -45,6 +48,7 @@ error_names = { REALM_NOT_FOUND: 'REALM_NOT_FOUND', NOT_IPA_SERVER: 'NOT_IPA_SERVER', NO_ACCESS_TO_LDAP: 'NO_ACCESS_TO_LDAP', + NO_TLS_LDAP: 'NO_TLS_LDAP', BAD_HOST_CONFIG: 'BAD_HOST_CONFIG', UNKNOWN_ERROR: 'UNKNOWN_ERROR', } @@ -135,7 +139,7 @@ class IPADiscovery(object): domain = domain[p+1:] return (None, None) - def search(self, domain = "", server = "", hostname=None): + def search(self, domain = "", server = "", hostname=None, ca_cert_path=None): root_logger.debug("[IPA Discovery]") root_logger.debug( 'Starting IPA discovery with domain=%s, server=%s, hostname=%s', @@ -224,14 +228,14 @@ class IPADiscovery(object): ldapaccess = True if self.server: # check ldap now - ldapret = self.ipacheckldap(self.server, self.realm) + ldapret = self.ipacheckldap(self.server, self.realm, ca_cert_path=ca_cert_path) if ldapret[0] == 0: self.server = ldapret[1] self.realm = ldapret[2] self.server_source = self.realm_source = ( 'Discovered from LDAP DNS records in %s' % self.server) - elif ldapret[0] == NO_ACCESS_TO_LDAP: + elif ldapret[0] == NO_ACCESS_TO_LDAP or ldapret[0] == NO_TLS_LDAP: ldapaccess = False # If one of LDAP servers checked rejects access (maybe anonymous @@ -260,12 +264,10 @@ class IPADiscovery(object): return ldapret[0] - def ipacheckldap(self, thost, trealm): + def ipacheckldap(self, thost, trealm, ca_cert_path=None): """ Given a host and kerberos realm verify that it is an IPA LDAP - server hosting the realm. The connection is an SSL connection - so the remote IPA CA cert must be available at - http://HOST/ipa/config/ca.crt + server hosting the realm. Returns a list [errno, host, realm] or an empty list on error. Errno is an error number: @@ -279,31 +281,17 @@ class IPADiscovery(object): i = 0 - # Get the CA certificate - try: - # Create TempDir - temp_ca_dir = tempfile.mkdtemp() - except OSError, e: - raise RuntimeError("Creating temporary directory failed: %s" % str(e)) - - try: - run(["/usr/bin/wget", "-O", "%s/ca.crt" % temp_ca_dir, "-T", "15", "-t", "2", - "http://%s/ipa/config/ca.crt" % format_netloc(thost)]) - except CalledProcessError, e: - root_logger.error('Retrieving CA from %s failed', thost) - root_logger.debug('Retrieving CA from %s failed: %s', thost, str(e)) - return [NOT_IPA_SERVER] - #now verify the server is really an IPA server try: ldap_url = "ldap://" + format_netloc(thost, 389) root_logger.debug("Init LDAP connection with: %s", ldap_url) lh = ldap.initialize(ldap_url) - ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, True) - ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, "%s/ca.crt" % temp_ca_dir) + if ca_cert_path: + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, True) + ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, ca_cert_path) + lh.set_option(ldap.OPT_X_TLS_DEMAND, True) + lh.start_tls_s() lh.set_option(ldap.OPT_PROTOCOL_VERSION, 3) - lh.set_option(ldap.OPT_X_TLS_DEMAND, True) - lh.start_tls_s() lh.simple_bind_s("","") # get IPA base DN @@ -358,14 +346,16 @@ class IPADiscovery(object): root_logger.debug("LDAP Error: Anonymous acces not allowed") return [NO_ACCESS_TO_LDAP] + # We should only get UNWILLING_TO_PERFORM if the remote LDAP server + # has minssf > 0 and we have attempted a non-TLS connection. + if ca_cert_path is None and isinstance(err, ldap.UNWILLING_TO_PERFORM): + root_logger.debug("LDAP server returned UNWILLING_TO_PERFORM. This likely means that minssf is enabled") + return [NO_TLS_LDAP] + root_logger.error("LDAP Error: %s: %s" % (err.args[0]['desc'], err.args[0].get('info', ''))) return [UNKNOWN_ERROR] - finally: - os.remove("%s/ca.crt" % temp_ca_dir) - os.rmdir(temp_ca_dir) - def ipadns_search_srv(self, domain, srv_record_name, default_port, break_on_first=True): |