From 12bfed37d4d22319e2cfadb5d9b460da7e748432 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Fri, 30 Sep 2011 10:09:55 +0200 Subject: Add a function for formatting network locations of the form host:port for use in URLs. If the host part is a literal IPv6 address, it must be enclosed in square brackets (RFC 2732). ticket 1869 --- install/tools/ipa-csreplica-manage | 8 ++++---- install/tools/ipa-replica-conncheck | 4 ++-- install/tools/ipa-replica-install | 6 +++--- install/tools/ipa-server-install | 2 +- ipa-client/ipa-install/ipa-client-install | 14 +++++++------- ipa-client/ipaclient/ipadiscovery.py | 8 ++++---- ipalib/rpc.py | 4 ++-- ipapython/dogtag.py | 6 +++--- ipapython/ipautil.py | 18 ++++++++++++++++++ ipaserver/install/bindinstance.py | 2 +- ipaserver/install/cainstance.py | 10 +++++----- ipaserver/install/dsinstance.py | 2 +- ipaserver/install/replication.py | 6 +++--- ipaserver/ipaldap.py | 7 ++++--- tests/test_ipaserver/test_ldap.py | 2 +- 15 files changed, 59 insertions(+), 40 deletions(-) diff --git a/install/tools/ipa-csreplica-manage b/install/tools/ipa-csreplica-manage index 39d505654..c33f3bc5f 100755 --- a/install/tools/ipa-csreplica-manage +++ b/install/tools/ipa-csreplica-manage @@ -111,7 +111,7 @@ class CSReplicationManager(replication.ReplicationManager): dn = 'cn=%s,cn=mapping tree,cn=config' % esc1_suffix # TODO: should we detect proto/port somehow ? mod = [(ldap.MOD_DELETE, 'nsslapd-referral', - 'ldap://%s:%s/%s' % (hostname, PORT, esc2_suffix))] + 'ldap://%s/%s' % (ipautil.format_netloc(hostname, PORT), esc2_suffix))] try: self.conn.modify_s(dn, mod) @@ -226,7 +226,7 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False): except errors.NotFound: sys.exit("'%s' has no replication agreement for '%s'" % (replica1, replica2)) except ldap.SERVER_DOWN, e: - sys.exit("Unable to connect to %s:%d: %s" % (replica1, PORT, convert_error(e))) + sys.exit("Unable to connect to %s: %s" % (ipautil.format_netloc(replica1, PORT), convert_error(e))) except Exception, e: sys.exit("Failed to get data from '%s': %s" % (replica1, convert_error(e))) @@ -322,7 +322,7 @@ def add_link(realm, replica1, replica2, dirman_passwd, options): except ldap.NO_SUCH_OBJECT: sys.exit('%s does not have a CA configured.' % replica2) except ldap.SERVER_DOWN, e: - sys.exit("Unable to connect to %s:636: %s" % (replica2, convert_error(e))) + sys.exit("Unable to connect to %s: %s" % (ipautil.format_netloc(replica2, 636), convert_error(e))) except Exception, e: sys.exit("Failed to get data from '%s': %s" % (replica1, convert_error(e))) @@ -337,7 +337,7 @@ def add_link(realm, replica1, replica2, dirman_passwd, options): except ldap.NO_SUCH_OBJECT: sys.exit("Cannot find replica '%s'" % replica1) except ldap.SERVER_DOWN, e: - sys.exit("Unable to connect to %s:%d %s" % (replica1, PORT, convert_error(e))) + sys.exit("Unable to connect to %s %s" % (ipautil.format_netloc(replica1, PORT), convert_error(e))) except Exception, e: sys.exit("Failed to get data from '%s': %s" % (replica1, convert_error(e))) diff --git a/install/tools/ipa-replica-conncheck b/install/tools/ipa-replica-conncheck index 48ff336ff..09567d6eb 100755 --- a/install/tools/ipa-replica-conncheck +++ b/install/tools/ipa-replica-conncheck @@ -201,8 +201,8 @@ def configure_krb5_conf(realm, kdc, filename): #the following are necessary only if DNS discovery does not work #[realms] - realms_info =[{'name':'kdc', 'type':'option', 'value':kdc+':88'}, - {'name':'admin_server', 'type':'option', 'value':kdc+':749'}] + realms_info =[{'name':'kdc', 'type':'option', 'value':ipautil.format_netloc(kdc, 88)}, + {'name':'admin_server', 'type':'option', 'value':ipautil.format_netloc(kdc, 749)}] realms = [{'name':realm, 'type':'subsection', 'value':realms_info}] opts.append({'name':'realms', 'type':'section', 'value':realms}) diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install index af317cde5..624e6ea82 100755 --- a/install/tools/ipa-replica-install +++ b/install/tools/ipa-replica-install @@ -227,7 +227,7 @@ def install_dns_records(config, options): # before our DS server is installed. cur_uri = api.Backend.ldap2.ldap_uri object.__setattr__(api.Backend.ldap2, 'ldap_uri', - 'ldaps://%s' % config.master_host_name) + 'ldaps://%s' % ipautil.format_netloc(config.master_host_name)) api.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=config.dirman_password, tls_cacertfile=CACERT) @@ -355,7 +355,7 @@ def main(): fd.write("basedn=" + util.realm_to_suffix(config.realm_name) + "\n") fd.write("realm=" + config.realm_name + "\n") fd.write("domain=" + config.domain_name + "\n") - fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % config.host_name) + fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % ipautil.format_netloc(config.host_name)) fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" % dsinstance.realm_to_serverid(config.realm_name)) if ipautil.file_exists(config.dir + "/cacert.p12"): fd.write("enable_ra=True\n") @@ -392,7 +392,7 @@ def main(): install_ca_cert(config) # Try out the password - ldapuri = 'ldaps://%s' % config.master_host_name + ldapuri = 'ldaps://%s' % ipautil.format_netloc(config.master_host_name) try: conn = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn='') conn.connect(bind_dn='cn=directory manager', diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install index 7d961cb87..36efd2b82 100755 --- a/install/tools/ipa-server-install +++ b/install/tools/ipa-server-install @@ -830,7 +830,7 @@ def main(): fd.write("basedn=" + util.realm_to_suffix(realm_name) + "\n") fd.write("realm=" + realm_name + "\n") fd.write("domain=" + domain_name + "\n") - fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % host_name) + fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % format_netloc(host_name)) fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" % dsinstance.realm_to_serverid(realm_name)) fd.write("enable_ra=True\n") if not options.selfsign: diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install index 5df420800..8e12d05fd 100755 --- a/ipa-client/ipa-install/ipa-client-install +++ b/ipa-client/ipa-install/ipa-client-install @@ -352,7 +352,7 @@ def configure_ipa_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server): {'name':'realm', 'type':'option', 'value':cli_realm}, {'name':'domain', 'type':'option', 'value':cli_domain}, {'name':'server', 'type':'option', 'value':cli_server}, - {'name':'xmlrpc_uri', 'type':'option', 'value':'https://%s/ipa/xml' % cli_server}, + {'name':'xmlrpc_uri', 'type':'option', 'value':'https://%s/ipa/xml' % ipautil.format_netloc(cli_server)}, {'name':'enable_ra', 'type':'option', 'value':'True'}] opts.append({'name':'global', 'type':'section', 'value':defopts}) @@ -389,7 +389,7 @@ def configure_ldap_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, d if options.on_master: opts.append({'name':'uri', 'type':'option', 'value':'ldap://localhost'}) else: - opts.append({'name':'uri', 'type':'option', 'value':'ldap://'+cli_server}) + opts.append({'name':'uri', 'type':'option', 'value':'ldap://'+ipautil.format_netloc(cli_server)}) else: opts.append({'name':'nss_srv_domain', 'type':'option', 'value':cli_domain}) @@ -428,7 +428,7 @@ def configure_nslcd_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, if options.on_master: opts.append({'name':'uri', 'type':'option', 'value':'ldap://localhost'}) else: - opts.append({'name':'uri', 'type':'option', 'value':'ldap://'+cli_server}) + opts.append({'name':'uri', 'type':'option', 'value':'ldap://'+ipautil.format_netloc(cli_server)}) else: opts.append({'name':'uri', 'type':'option', 'value':'DNS'}) @@ -471,7 +471,7 @@ def hardcode_ldap_server(cli_server): ldapconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer") ldapconf.setOptionAssignment(" ") - opts = [{'name':'uri', 'type':'option', 'action':'set', 'value':'ldap://'+cli_server}, + opts = [{'name':'uri', 'type':'option', 'action':'set', 'value':'ldap://'+ipautil.format_netloc(cli_server)}, {'name':'empty', 'type':'empty'}] # Errors raised by this should be caught by the caller @@ -509,8 +509,8 @@ def configure_krb5_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, c #the following are necessary only if DNS discovery does not work if not dnsok or not cli_kdc or options.force: #[realms] - kropts =[{'name':'kdc', 'type':'option', 'value':cli_server+':88'}, - {'name':'admin_server', 'type':'option', 'value':cli_server+':749'}, + kropts =[{'name':'kdc', 'type':'option', 'value':ipautil.format_netloc(cli_server, 88)}, + {'name':'admin_server', 'type':'option', 'value':ipautil.format_netloc(cli_server, 749)}, {'name':'default_domain', 'type':'option', 'value':cli_domain}] else: kropts = [] @@ -887,7 +887,7 @@ def install(options, env, fstore, statestore): pass try: - run(["/usr/bin/wget", "-O", "/etc/ipa/ca.crt", "http://%s/ipa/config/ca.crt" % cli_server]) + run(["/usr/bin/wget", "-O", "/etc/ipa/ca.crt", "http://%s/ipa/config/ca.crt" % ipautil.format_netloc(cli_server)]) except CalledProcessError, e: print 'Retrieving CA from %s failed.\n%s' % (cli_server, str(e)) return CLIENT_INSTALL_ERROR diff --git a/ipa-client/ipaclient/ipadiscovery.py b/ipa-client/ipaclient/ipadiscovery.py index f6c13fb67..3e31cad37 100644 --- a/ipa-client/ipaclient/ipadiscovery.py +++ b/ipa-client/ipaclient/ipadiscovery.py @@ -25,7 +25,7 @@ import tempfile import ldap from ldap import LDAPError from ipapython.ipautil import run, CalledProcessError, valid_ip, get_ipa_basedn, \ - realm_to_suffix + realm_to_suffix, format_netloc NOT_FQDN = -1 @@ -220,15 +220,15 @@ class IPADiscovery: raise RuntimeError("Creating temporary directory failed: %s" % str(e)) try: - run(["/usr/bin/wget", "-O", "%s/ca.crt" % temp_ca_dir, "http://%s/ipa/config/ca.crt" % thost]) + run(["/usr/bin/wget", "-O", "%s/ca.crt" % temp_ca_dir, "http://%s/ipa/config/ca.crt" % format_netloc(thost)]) except CalledProcessError, e: logging.debug('Retrieving CA from %s failed.\n%s' % (thost, str(e))) return [NOT_IPA_SERVER] #now verify the server is really an IPA server try: - logging.debug("Init ldap with: ldap://"+thost+":389") - lh = ldap.initialize("ldap://"+thost+":389") + logging.debug("Init ldap with: ldap://"+format_netloc(thost, 389)) + lh = ldap.initialize("ldap://"+format_netloc(thost, 389)) ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, True) ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, "%s/ca.crt" % temp_ca_dir) lh.set_option(ldap.OPT_PROTOCOL_VERSION, 3) diff --git a/ipalib/rpc.py b/ipalib/rpc.py index 5491b28da..f8e4d9e6a 100644 --- a/ipalib/rpc.py +++ b/ipalib/rpc.py @@ -306,7 +306,7 @@ class xmlclient(Connectible): scheme = "https" else: scheme = "http" - server = '%s://%s%s' % (scheme, self.conn._ServerProxy__host, self.conn._ServerProxy__handler) + server = '%s://%s%s' % (scheme, ipautil.format_netloc(self.conn._ServerProxy__host), self.conn._ServerProxy__handler) return server def get_url_list(self): @@ -321,7 +321,7 @@ class xmlclient(Connectible): for r in rs: if r.dns_type == dnsclient.DNS_T_SRV: rsrv = r.rdata.server.rstrip('.') - servers.append('https://%s%s' % (rsrv, path)) + servers.append('https://%s%s' % (ipautil.format_netloc(rsrv), path)) servers = list(set(servers)) # the list/set conversion won't preserve order so stick in the # local config file version here. diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py index 02f981974..c5317166a 100644 --- a/ipapython/dogtag.py +++ b/ipapython/dogtag.py @@ -20,7 +20,7 @@ from ipalib import api, errors import httplib import xml.dom.minidom -from ipapython import nsslib +from ipapython import nsslib, ipautil import nss.nss as nss from nss.error import NSPRError from ipalib.errors import NetworkError, CertificateOperationError @@ -72,7 +72,7 @@ def https_request(host, port, url, secdir, password, nickname, **kw): """ if isinstance(host, unicode): host = host.encode('utf-8') - uri = 'https://%s:%d%s' % (host, port, url) + uri = 'https://%s%s' % (ipautil.format_netloc(host, port), url) post = urlencode(kw) logging.info('sslget %r', uri) logging.debug('sslget post %r', post) @@ -110,7 +110,7 @@ def http_request(host, port, url, **kw): """ if isinstance(host, unicode): host = host.encode('utf-8') - uri = 'http://%s:%s%s' % (host, port, url) + uri = 'http://%s%s' % (ipautil.format_netloc(host, port), url) post = urlencode(kw) logging.info('request %r', uri) logging.debug('request post %r', post) diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py index cfc979edb..dfeaa9e0b 100644 --- a/ipapython/ipautil.py +++ b/ipapython/ipautil.py @@ -151,6 +151,24 @@ class CheckedIPAddress(netaddr.IPAddress): def valid_ip(addr): return netaddr.valid_ipv4(addr) or netaddr.valid_ipv6(addr) +def format_netloc(host, port=None): + """ + Format network location (host:port). + + If the host part is a literal IPv6 address, it must be enclosed in square + brackets (RFC 2732). + """ + host = str(host) + try: + socket.inet_pton(socket.AF_INET6, host) + host = '[%s]' % host + except socket.error: + pass + if port is None: + return host + else: + return '%s:%s' % (host, str(port)) + def realm_to_suffix(realm_name): s = realm_name.split(".") terms = ["dc=" + x.lower() for x in s] diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py index cdf7b939d..f9bd3a84e 100644 --- a/ipaserver/install/bindinstance.py +++ b/ipaserver/install/bindinstance.py @@ -96,7 +96,7 @@ def dns_container_exists(fqdn, suffix): return True try: - server = ldap.initialize("ldap://" + fqdn) + server = ldap.initialize("ldap://" + ipautil.format_netloc(fqdn)) server.simple_bind_s() except ldap.SERVER_DOWN: raise RuntimeError('LDAP server on %s is not responding. Is IPA installed?' % fqdn) diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py index 6a86e8ccc..d244097d8 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py @@ -663,7 +663,7 @@ class CAInstance(service.Service): args.append("-clone_start_tls") args.append("true") args.append("-clone_uri") - args.append("https://%s:%d" % (self.master_host, 443)) + args.append("https://%s" % ipautil.format_netloc(self.master_host, 443)) else: args.append("-clone") args.append("false") @@ -747,7 +747,7 @@ class CAInstance(service.Service): '-p', self.admin_password, '-d', self.ca_agent_db, '-r', '/ca/agent/ca/profileReview?requestId=%s' % self.requestId, - '%s:%d' % (self.fqdn, AGENT_SECURE_PORT), + '%s' % ipautil.format_netloc(self.fqdn, AGENT_SECURE_PORT), ] (stdout, stderr, returncode) = ipautil.run(args, nolog=(self.admin_password,)) @@ -767,7 +767,7 @@ class CAInstance(service.Service): '-d', self.ca_agent_db, '-e', params, '-r', '/ca/agent/ca/profileProcess', - '%s:%d' % (self.fqdn, AGENT_SECURE_PORT), + '%s' % ipautil.format_netloc(self.fqdn, AGENT_SECURE_PORT), ] (stdout, stderr, returncode) = ipautil.run(args, nolog=(self.admin_password,)) @@ -810,7 +810,7 @@ class CAInstance(service.Service): # Create an RA user in the CA LDAP server and add that user to # the appropriate groups so it can issue certificates without # manual intervention. - ld = ldap.initialize("ldap://%s:%d" % (self.fqdn, self.ds_port)) + ld = ldap.initialize("ldap://%s" % ipautil.format_netloc(self.fqdn, self.ds_port)) ld.protocol_version=ldap.VERSION3 ld.simple_bind_s("cn=Directory Manager", self.dm_password) @@ -1035,7 +1035,7 @@ class CAInstance(service.Service): installutils.set_directive(caconfig, 'ca.publish.rule.instance.LdapXCertRule.enable', 'false', quotes=False, separator='=') # Fix the CRL URI in the profile - installutils.set_directive('/var/lib/%s/profiles/ca/caIPAserviceCert.cfg' % PKI_INSTANCE_NAME, 'policyset.serverCertSet.9.default.params.crlDistPointsPointName_0', 'https://%s/ipa/crl/MasterCRL.bin' % self.fqdn, quotes=False, separator='=') + installutils.set_directive('/var/lib/%s/profiles/ca/caIPAserviceCert.cfg' % PKI_INSTANCE_NAME, 'policyset.serverCertSet.9.default.params.crlDistPointsPointName_0', 'https://%s/ipa/crl/MasterCRL.bin' % ipautil.format_netloc(self.fqdn), quotes=False, separator='=') ipaservices.restore_context(publishdir) diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index 790b560b9..f2b16dfe8 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -112,7 +112,7 @@ def is_ds_running(): def has_managed_entries(host_name, dm_password): """Check to see if the Managed Entries plugin is available""" - ldapuri = 'ldap://%s' % host_name + ldapuri = 'ldap://%s' % ipautil.format_netloc(host_name) conn = None try: conn = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn='cn=config') diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py index 986fb5e83..a6bd7af37 100644 --- a/ipaserver/install/replication.py +++ b/ipaserver/install/replication.py @@ -319,7 +319,7 @@ class ReplicationManager(object): return cn def to_ldap_url(self, conn): - return "ldap://%s:%d/" % (conn.host, conn.port) + return "ldap://%s/" % ipautil.format_netloc(conn.host, conn.port) def setup_chaining_farm(self, conn): try: @@ -544,7 +544,7 @@ class ReplicationManager(object): dn = 'cn=%s,cn=mapping tree,cn=config' % esc1_suffix # TODO: should we detect proto/port somehow ? mod = [(ldap.MOD_DELETE, 'nsslapd-referral', - 'ldap://%s:389/%s' % (hostname, esc2_suffix))] + 'ldap://%s/%s' % (ipautil.format_netloc(hostname, 389), esc2_suffix))] try: self.conn.modify_s(dn, mod) @@ -700,7 +700,7 @@ class ReplicationManager(object): self.ad_suffix = "" try: # Validate AD connection - ad_conn = ldap.initialize('ldap://%s' % ad_dc_name) + ad_conn = ldap.initialize('ldap://%s' % ipautil.format_netloc(ad_dc_name)) #the next one is to workaround bugs arounf opendalp libs+NSS db ad_conn.set_option(ldap.OPT_X_TLS_NEWCTX, 0) ad_conn.set_option(ldap.OPT_X_TLS_CACERTFILE, cacert) diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py index 4de09f1e5..5477417ac 100644 --- a/ipaserver/ipaldap.py +++ b/ipaserver/ipaldap.py @@ -34,6 +34,7 @@ from ldap.controls import LDAPControl,DecodeControlTuples,EncodeControlTuples from ldap.ldapobject import SimpleLDAPObject from ipaserver import ipautil from ipalib import errors +from ipapython.ipautil import format_netloc # Global variable to define SASL auth SASL_AUTH = ldap.sasl.sasl({},'GSSAPI') @@ -215,12 +216,12 @@ class IPAdmin(SimpleLDAPObject): its own encryption. """ if self.cacert is not None: - SimpleLDAPObject.__init__(self,'ldaps://%s:%d' % (self.host,self.port)) + SimpleLDAPObject.__init__(self,'ldaps://%s' % format_netloc(self.host, self.port)) else: if self.ldapi: SimpleLDAPObject.__init__(self,'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % "-".join(self.realm.split("."))) else: - SimpleLDAPObject.__init__(self,'ldap://%s:%d' % (self.host,self.port)) + SimpleLDAPObject.__init__(self,'ldap://%s' % format_netloc(self.host, self.port)) def __init__(self,host='',port=389,cacert=None,bindcert=None,bindkey=None,proxydn=None,debug=None,ldapi=False,realm=None): """We just set our instance variables and wrap the methods - the real @@ -330,7 +331,7 @@ class IPAdmin(SimpleLDAPObject): raise errors.DatabaseError(desc=desc,info=info) def toLDAPURL(self): - return "ldap://%s:%d/" % (self.host,self.port) + return "ldap://%s/" % format_netloc(self.host, self.port) def set_proxydn(self, proxydn): self.proxydn = proxydn diff --git a/tests/test_ipaserver/test_ldap.py b/tests/test_ipaserver/test_ldap.py index 568a37acd..b3f8009f9 100644 --- a/tests/test_ipaserver/test_ldap.py +++ b/tests/test_ipaserver/test_ldap.py @@ -42,7 +42,7 @@ class test_ldap(object): def setUp(self): self.conn = None - self.ldapuri = 'ldap://%s' % api.env.host + self.ldapuri = 'ldap://%s' % ipautil.format_netloc(api.env.host) self.ccache = '/tmp/krb5cc_%d' % os.getuid() nss.nss_init_nodb() self.dn = str(DN(('krbprincipalname','ldap/%s@%s' % (api.env.host, api.env.realm)), -- cgit