URL: https://github.com/freeipa/freeipa/pull/428 Author: MartinBasti Title: #428: [WIP] [Py3] ipa-server-install Action: synchronized
To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/428/head:pr428 git checkout pr428
From 4d367dfa6e02858132f62e5695714939310c1637 Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Fri, 27 Jan 2017 17:00:42 +0100 Subject: [PATCH 01/11] py3: modify_s: attribute name must be str not bytes https://fedorahosted.org/freeipa/ticket/4985 --- ipapython/ipaldap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py index 37d23d7..3df82b3 100644 --- a/ipapython/ipaldap.py +++ b/ipapython/ipaldap.py @@ -727,7 +727,7 @@ def modify_s(self, dn, modlist): # FIXME: for backwards compatibility only assert isinstance(dn, DN) dn = str(dn) - modlist = [(a, self.encode(b), self.encode(c)) for a, b, c in modlist] + modlist = [(a, b, self.encode(c)) for a, b, c in modlist] return self.conn.modify_s(dn, modlist) @property From 9a045ddb67760192766923cd5a597227d5a4edda Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Fri, 27 Jan 2017 17:33:44 +0100 Subject: [PATCH 02/11] py3: configparser: use raw keyword configparser.get() changed in python3 and `raw` is now a keyword attribute. Also it must be set to True, otherwise InterpolationSyntaxError is raised ''' InterpolationSyntaxError: '%' must be followed by '%' or '(', found: '%2fvar%2frun%2fslapd-EXAMPLE-COM.socket' ''' https://fedorahosted.org/freeipa/ticket/4985 --- ipaserver/secrets/kem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipaserver/secrets/kem.py b/ipaserver/secrets/kem.py index 143caaf..3577975 100644 --- a/ipaserver/secrets/kem.py +++ b/ipaserver/secrets/kem.py @@ -181,7 +181,7 @@ def __init__(self, config=None, ipaconf=paths.IPA_DEFAULT_CONF): self.realm = conf.get('global', 'realm') self.ldap_uri = config.get('ldap_uri', None) if self.ldap_uri is None: - self.ldap_uri = conf.get('global', 'ldap_uri', None) + self.ldap_uri = conf.get('global', 'ldap_uri', raw=True) self._server_keys = None def find_key(self, kid, usage): From 7dcd8723ef638c23b7d22a0f36cf242cc8aef71c Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Fri, 27 Jan 2017 18:10:37 +0100 Subject: [PATCH 03/11] py3: custodia: basedn must be unicode basedn in custodia related modules has type bytes, that causes issues in Py3 when strings were concatenated with bytes ``` malformed RDN string = "cn=custodia,cn=ipa,cn=etc,b'dc=example,dc=com'" ``` https://fedorahosted.org/freeipa/ticket/4985 --- ipaserver/secrets/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipaserver/secrets/common.py b/ipaserver/secrets/common.py index 2b906b6..f3dc320 100644 --- a/ipaserver/secrets/common.py +++ b/ipaserver/secrets/common.py @@ -23,7 +23,7 @@ def basedn(self): if self._basedn is None: conn = self.connect() r = conn.search_s('', ldap.SCOPE_BASE) - self._basedn = r[0][1]['defaultnamingcontext'][0] + self._basedn = r[0][1]['defaultnamingcontext'][0].decode('utf-8') return self._basedn def connect(self): From b07246ffe79a5dd00a9ab02c7f6ae23260e4cecd Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Tue, 31 Jan 2017 18:11:42 +0100 Subject: [PATCH 04/11] py3: kem.py: user bytes with ldap values python ldap requires bytes as values https://fedorahosted.org/freeipa/ticket/4985 --- ipaserver/secrets/kem.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ipaserver/secrets/kem.py b/ipaserver/secrets/kem.py index 3577975..5d784b7 100644 --- a/ipaserver/secrets/kem.py +++ b/ipaserver/secrets/kem.py @@ -130,13 +130,13 @@ def set_key(self, usage, principal, key): service_rdn = ('cn', servicename) if servicename != 'host' else DN() dn = str(DN(('cn', name), service_rdn, self.keysbase)) try: - mods = [('objectClass', ['nsContainer', - 'ipaKeyPolicy', - 'ipaPublicKeyObject', - 'groupOfPrincipals']), - ('cn', name), - ('ipaKeyUsage', RFC5280_USAGE_MAP[usage]), - ('memberPrincipal', principal), + mods = [('objectClass', [b'nsContainer', + b'ipaKeyPolicy', + b'ipaPublicKeyObject', + b'groupOfPrincipals']), + ('cn', name.encode('utf-8')), + ('ipaKeyUsage', RFC5280_USAGE_MAP[usage].encode('utf-8')), + ('memberPrincipal', principal.encode('utf-8')), ('ipaPublicKey', public_key)] conn.add_s(dn, mods) except Exception: # pylint: disable=broad-except From f3185832501737acfc3ed349760dc48680def8c4 Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Tue, 31 Jan 2017 18:14:33 +0100 Subject: [PATCH 05/11] custodia: kem.set_keys: replace too-broad exception Exception is too brod and may hide various issues that show up later. If the code expects that entry may exist, then ldap.ALREADY_EXISTS exception should be used --- ipaserver/secrets/kem.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ipaserver/secrets/kem.py b/ipaserver/secrets/kem.py index 5d784b7..28fb4d3 100644 --- a/ipaserver/secrets/kem.py +++ b/ipaserver/secrets/kem.py @@ -139,8 +139,7 @@ def set_key(self, usage, principal, key): ('memberPrincipal', principal.encode('utf-8')), ('ipaPublicKey', public_key)] conn.add_s(dn, mods) - except Exception: # pylint: disable=broad-except - # This may fail if the entry already exists + except ldap.ALREADY_EXISTS: mods = [(ldap.MOD_REPLACE, 'ipaPublicKey', public_key)] conn.modify_s(dn, mods) From a651d0f423a21cce11e5f611208f54aa34d4176d Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Tue, 31 Jan 2017 18:36:24 +0100 Subject: [PATCH 06/11] py3: upgradeinstance: open dse.ldif in textual mode ldap ldif parser requires to have input file opened in textual mode https://fedorahosted.org/freeipa/ticket/4985 --- ipaserver/install/upgradeinstance.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py index 8e28436..b244898 100644 --- a/ipaserver/install/upgradeinstance.py +++ b/ipaserver/install/upgradeinstance.py @@ -124,7 +124,7 @@ def create_instance(self): def __save_config(self): shutil.copy2(self.filename, self.savefilename) - with open(self.filename, "rb") as in_file: + with open(self.filename, "r") as in_file: parser = GetEntryFromLDIF(in_file, entries_dn=["cn=config"]) parser.parse() try: @@ -156,8 +156,8 @@ def __save_config(self): def __enable_ds_global_write_lock(self): ldif_outfile = "%s.modified.out" % self.filename - with open(ldif_outfile, "wb") as out_file: - with open(self.filename, "rb") as in_file: + with open(ldif_outfile, "w") as out_file: + with open(self.filename, "r") as in_file: parser = installutils.ModifyLDIF(in_file, out_file) parser.replace_value( @@ -172,8 +172,8 @@ def __restore_config(self): global_lock = self.restore_state('nsslapd-global-backend-lock') ldif_outfile = "%s.modified.out" % self.filename - with open(ldif_outfile, "wb") as out_file: - with open(self.filename, "rb") as in_file: + with open(ldif_outfile, "w") as out_file: + with open(self.filename, "r") as in_file: parser = installutils.ModifyLDIF(in_file, out_file) if port is not None: @@ -194,8 +194,8 @@ def __restore_config(self): def __disable_listeners(self): ldif_outfile = "%s.modified.out" % self.filename - with open(ldif_outfile, "wb") as out_file: - with open(self.filename, "rb") as in_file: + with open(ldif_outfile, "w") as out_file: + with open(self.filename, "r") as in_file: parser = installutils.ModifyLDIF(in_file, out_file) parser.replace_value("cn=config", "nsslapd-port", ["0"]) parser.replace_value("cn=config", "nsslapd-security", ["off"]) From 970d893c0fefee32cf61a67170789789def63400 Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Tue, 31 Jan 2017 18:53:47 +0100 Subject: [PATCH 07/11] py3: upgradeinstance: decode data before storing them as backup... ...and vice versa backup requires string not bytes, but ldap provide bytes thus data must be decoded and encoded from restore https://fedorahosted.org/freeipa/ticket/4985 --- ipaserver/install/upgradeinstance.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py index b244898..8e6c87d 100644 --- a/ipaserver/install/upgradeinstance.py +++ b/ipaserver/install/upgradeinstance.py @@ -134,21 +134,22 @@ def __save_config(self): self.filename) try: - port = config_entry['nsslapd-port'][0] + port = config_entry['nsslapd-port'][0].decode('utf-8') except KeyError: pass else: self.backup_state('nsslapd-port', port) try: - security = config_entry['nsslapd-security'][0] + security = config_entry['nsslapd-security'][0].decode('utf-8') except KeyError: pass else: self.backup_state('nsslapd-security', security) try: - global_lock = config_entry['nsslapd-global-backend-lock'][0] + global_lock = config_entry[ + 'nsslapd-global-backend-lock'][0].decode('utf-8') except KeyError: pass else: @@ -177,16 +178,17 @@ def __restore_config(self): parser = installutils.ModifyLDIF(in_file, out_file) if port is not None: - parser.replace_value("cn=config", "nsslapd-port", [port]) + parser.replace_value( + "cn=config", "nsslapd-port", [port.encode('utf-8')]) if security is not None: parser.replace_value("cn=config", "nsslapd-security", - [security]) + [security.encode('utf-8')]) # disable global lock by default parser.remove_value("cn=config", "nsslapd-global-backend-lock") if global_lock is not None: parser.add_value("cn=config", "nsslapd-global-backend-lock", - [global_lock]) + [global_lock.encode('utf-8')]) parser.parse() From 41e271789e4a93db4f5235b17c9c85702b8406ac Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Tue, 31 Jan 2017 19:23:39 +0100 Subject: [PATCH 08/11] py3: upgradeinstance: use bytes literals with LDIF operations python ldif support only bytes as values, literals must be bytes https://fedorahosted.org/freeipa/ticket/4985 --- ipaserver/install/upgradeinstance.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py index 8e6c87d..fca4226 100644 --- a/ipaserver/install/upgradeinstance.py +++ b/ipaserver/install/upgradeinstance.py @@ -162,7 +162,7 @@ def __enable_ds_global_write_lock(self): parser = installutils.ModifyLDIF(in_file, out_file) parser.replace_value( - "cn=config", "nsslapd-global-backend-lock", ["on"]) + "cn=config", "nsslapd-global-backend-lock", [b"on"]) parser.parse() shutil.copy2(ldif_outfile, self.filename) @@ -199,8 +199,8 @@ def __disable_listeners(self): with open(ldif_outfile, "w") as out_file: with open(self.filename, "r") as in_file: parser = installutils.ModifyLDIF(in_file, out_file) - parser.replace_value("cn=config", "nsslapd-port", ["0"]) - parser.replace_value("cn=config", "nsslapd-security", ["off"]) + parser.replace_value("cn=config", "nsslapd-port", [b"0"]) + parser.replace_value("cn=config", "nsslapd-security", [b"off"]) parser.remove_value("cn=config", "nsslapd-ldapientrysearchbase") parser.parse() From 56d35089313f3a1a56e65eb0757c49b7b918495d Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Tue, 31 Jan 2017 19:59:31 +0100 Subject: [PATCH 09/11] py3: create DNS zonefile: use textual mode Also code was rewritten to use NamedTemporaryFile with context https://fedorahosted.org/freeipa/ticket/4985 --- ipaserver/install/bindinstance.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py index e24249a..10a37b9 100644 --- a/ipaserver/install/bindinstance.py +++ b/ipaserver/install/bindinstance.py @@ -668,10 +668,13 @@ def create_file_with_system_records(self): system_records.get_base_records() ) ) - [fd, name] = tempfile.mkstemp(".db","ipa.system.records.") - os.write(fd, text) - os.close(fd) - print("Please add records in this file to your DNS system:", name) + with tempfile.NamedTemporaryFile( + mode="w", prefix="ipa.system.records.", + suffix=".db", delete=False + ) as f: + f.write(text) + print("Please add records in this file to your DNS system:", + f.name) def create_instance(self): From 6401eb82de00b65476d674240ac2c954484d8d4a Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Tue, 31 Jan 2017 20:27:11 +0100 Subject: [PATCH 10/11] py3: change_admin_password: use textual mode Convert function to NamedTemporaryFile with textual mode, because passwords are text. Using `with` and NamedTemporaryFile gives more security agains leaking password from tempfiles. https://fedorahosted.org/freeipa/ticket/4985 --- ipaserver/install/dsinstance.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index ceb7bf3..8e979a7 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -951,21 +951,19 @@ def add_hbac(self): def change_admin_password(self, password): root_logger.debug("Changing admin password") - dmpwdfile = "" - admpwdfile = "" - try: - (dmpwdfd, dmpwdfile) = tempfile.mkstemp(dir=paths.VAR_LIB_IPA) - os.write(dmpwdfd, self.dm_password) - os.close(dmpwdfd) + dir_ipa = paths.VAR_LIB_IPA + with tempfile.NamedTemporaryFile("w", dir=dir_ipa) as dmpwdfile, \ + tempfile.NamedTemporaryFile("w", dir=dir_ipa) as admpwdfile: + dmpwdfile.write(self.dm_password) + dmpwdfile.flush() - (admpwdfd, admpwdfile) = tempfile.mkstemp(dir=paths.VAR_LIB_IPA) - os.write(admpwdfd, password) - os.close(admpwdfd) + admpwdfile.write(password) + admpwdfile.flush() args = [paths.LDAPPASSWD, "-h", self.fqdn, "-ZZ", "-x", "-D", str(DN(('cn', 'Directory Manager'))), - "-y", dmpwdfile, "-T", admpwdfile, + "-y", dmpwdfile.name, "-T", admpwdfile.name, str(DN(('uid', 'admin'), ('cn', 'users'), ('cn', 'accounts'), self.suffix))] try: env = {'LDAPTLS_CACERTDIR': os.path.dirname(paths.IPA_CA_CRT), @@ -976,12 +974,6 @@ def change_admin_password(self, password): print("Unable to set admin password", e) root_logger.debug("Unable to set admin password %s" % e) - finally: - if os.path.isfile(dmpwdfile): - os.remove(dmpwdfile) - if os.path.isfile(admpwdfile): - os.remove(admpwdfile) - def uninstall(self): if self.is_configured(): self.print_msg("Unconfiguring directory server") From ed59e062cf76df8571ced0d630e197751a18f060 Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Tue, 7 Feb 2017 19:24:46 +0100 Subject: [PATCH 11/11] py3: ipa_generate_password: do not compare None and Int The one cannot compare None and Int in Py3 """ unorderable types: NoneType() > int() """ This change should work with both None and Int. https://fedorahosted.org/freeipa/ticket/4985 --- ipapython/ipautil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py index c810adc..8f8c37b 100644 --- a/ipapython/ipautil.py +++ b/ipapython/ipautil.py @@ -859,7 +859,7 @@ def ipa_generate_password(entropy_bits=256, uppercase=1, lowercase=1, digits=1, # NSS function sftk_newPinCheck() in nss/lib/softoken/fipstokn.c. for charclass_name in ['digits', 'uppercase', 'lowercase', 'special']: charclass = pwd_charsets[charclass_name] - todo_characters = req_classes[charclass_name] + todo_characters = req_classes[charclass_name] or 0 while todo_characters > 0: password += rnd.choice(charclass['chars']) todo_entropy -= charclass['entropy']
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code