Hi, For the dates older than 1900, Python is unable to convert the datetime representation to string using strftime:
https://bugs.python.org/issue1777412 Work around the issue adding a custom method to convert the datetime objects to LDAP generalized time strings. https://fedorahosted.org/freeipa/ticket/5579 Tomas
From d746dd233c07b0dc81f539f502844a16e5cc97e2 Mon Sep 17 00:00:00 2001 From: Tomas Babej <tba...@redhat.com> Date: Fri, 15 Jan 2016 12:20:12 +0100 Subject: [PATCH] ipapython: Use custom datetime to LDAP generalized time converter For the dates older than 1900, Python is unable to convert the datetime representation to string using strftime: https://bugs.python.org/issue1777412 Work around the issue adding a custom method to convert the datetime objects to LDAP generalized time strings. https://fedorahosted.org/freeipa/ticket/5579 --- daemons/dnssec/ipa-ods-exporter | 5 +---- ipalib/cli.py | 5 +++-- ipalib/rpc.py | 6 +++--- ipapython/ipaldap.py | 4 ++-- ipapython/ipautil.py | 17 +++++++++++++++++ ipaserver/install/ipa_otptoken_import.py | 4 ++-- 6 files changed, 28 insertions(+), 13 deletions(-) diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter index 2aa936040c373e366e7e15539ed6e3413aac7d55..b2df53dee0ecb8cc08fcde9c20e17f72588b18de 100755 --- a/daemons/dnssec/ipa-ods-exporter +++ b/daemons/dnssec/ipa-ods-exporter @@ -83,9 +83,6 @@ def dnskey_flags_to_text_set(flags): mask <<= 1 return flags_set -def datetime2ldap(dt): - return dt.strftime(ipalib.constants.LDAP_GENERALIZED_TIME_FORMAT) - def sql2datetime(sql_time): """Convert SQL date format from local time zone into UTC.""" localtz = dateutil.tz.tzlocal() @@ -276,7 +273,7 @@ def get_ods_keys(zone_name): key_data.update(sql2ldap_algorithm(row['algorithm'])) key_id = "%s-%s-%s" % (key_type, - datetime2ldap(key_data['idnsSecKeyCreated']), + ipautil.datetime_to_ldap_gentime(key_data['idnsSecKeyCreated']), row['HSMkey_id']) key_data.update(sql2ldap_keyid(row['HSMkey_id'])) diff --git a/ipalib/cli.py b/ipalib/cli.py index 3b1b5a39371845d59bab07ac2fc32de598a469be..58fbf048fdda4278bec0846486837fd35a581526 100644 --- a/ipalib/cli.py +++ b/ipalib/cli.py @@ -56,11 +56,12 @@ from ipalib import plugable from ipalib.errors import (PublicError, CommandError, HelpError, InternalError, NoSuchNamespaceError, ValidationError, NotFound, NotConfiguredError, PromptFailed) -from ipalib.constants import CLI_TAB, LDAP_GENERALIZED_TIME_FORMAT +from ipalib.constants import CLI_TAB from ipalib.parameters import File, Str, Enum, Any, Flag from ipalib.text import _ from ipalib import api # pylint: disable=unused-import from ipapython.dnsutil import DNSName +from ipapython import ipautil import datetime @@ -169,7 +170,7 @@ class textui(backend.Backend): if type(value) is bytes: return base64.b64encode(value) elif type(value) is datetime.datetime: - return value.strftime(LDAP_GENERALIZED_TIME_FORMAT) + return ipautil.datetime_to_ldap_gentime(value) elif isinstance(value, DNSName): return unicode(value) else: diff --git a/ipalib/rpc.py b/ipalib/rpc.py index a165491adea5366a14a86d7c8bd6337e36fd1b44..a2ca7cb3374e28074332c8827ab51088cc83a5e7 100644 --- a/ipalib/rpc.py +++ b/ipalib/rpc.py @@ -185,7 +185,7 @@ def xml_wrap(value, version): if capabilities.client_has_capability(version, 'datetime_values'): return DateTime(value) else: - return value.strftime(LDAP_GENERALIZED_TIME_FORMAT) + return ipautil.datetime_to_ldap_gentime(value) if isinstance(value, DNSName): if capabilities.client_has_capability(version, 'dns_name_values'): @@ -304,9 +304,9 @@ def json_encode_binary(val, version): return str(val) elif isinstance(val, datetime.datetime): if capabilities.client_has_capability(version, 'datetime_values'): - return {'__datetime__': val.strftime(LDAP_GENERALIZED_TIME_FORMAT)} + return {'__datetime__': ipautil.datetime_to_ldap_gentime(val)} else: - return val.strftime(LDAP_GENERALIZED_TIME_FORMAT) + return ipautil.datetime_to_ldap_gentime(val) elif isinstance(val, DNSName): if capabilities.client_has_capability(version, 'dns_name_values'): return {'__dns_name__': unicode(val)} diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py index 28bfcb5c2ee2140d38f17248fc9c90861cd251e4..d916fd62698a0ff6fe023357238ec33b5ae099b9 100644 --- a/ipapython/ipaldap.py +++ b/ipapython/ipaldap.py @@ -38,7 +38,7 @@ import six from ipalib import errors, _ from ipalib.constants import LDAP_GENERALIZED_TIME_FORMAT -from ipapython.ipautil import ( +from ipapython.ipautil import (datetime_to_ldap_gentime, format_netloc, wait_for_open_socket, wait_for_open_ports, CIDict) from ipapython.ipa_log_manager import log_mgr from ipapython.dn import DN @@ -847,7 +847,7 @@ class LDAPClient(object): dct = dict((self.encode(k), self.encode(v)) for k, v in val.items()) return dct elif isinstance(val, datetime.datetime): - return val.strftime(LDAP_GENERALIZED_TIME_FORMAT) + return datetime_to_ldap_gentime(val) elif val is None: return None else: diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py index 7949bdf05cd72c512e6c2bc24b1bc52012e63317..1bdd4586c4918a45caed549b7aada7a83a4080c1 100644 --- a/ipapython/ipautil.py +++ b/ipapython/ipautil.py @@ -832,6 +832,23 @@ def parse_generalized_time(timestr): except ValueError: return None +def datetime_to_ldap_gentime(value): + """ + Converts a datetime.datetime instance to a string representation, + circumventing Python bug which occurs for dates older than 1900: + https://bugs.python.org/issue1777412 + + Note: The inverse conversion using strptime works fine even for + such dates, therefore a symmetric conversion function is not necessary. + """ + + if not isinstance(value, datetime.datetime): + raise ValueError("Only datetime.datetime can be converted to" + "LDAP generalized time") + + return ('{0.year:4d}{0.month:02d}{0.day:02d}{0.hour:02d}' + '{0.minute:02d}{0.second:02d}Z').format(value) + def ipa_generate_password(characters=None,pwd_len=None): ''' Generates password. Password cannot start or end with a whitespace character. It also cannot be formed by whitespace characters only. diff --git a/ipaserver/install/ipa_otptoken_import.py b/ipaserver/install/ipa_otptoken_import.py index 8ea67fce144f5058ed152378bd677e3f937583eb..731e9ae458865df9934f3c2dafb87254cfa54fd0 100644 --- a/ipaserver/install/ipa_otptoken_import.py +++ b/ipaserver/install/ipa_otptoken_import.py @@ -34,7 +34,7 @@ import gssapi import six from six.moves import xrange -from ipapython import admintool +from ipapython import admintool, ipautil from ipalib import api, errors from ipaserver.plugins.ldap2 import AUTOBIND_DISABLED @@ -409,7 +409,7 @@ class PSKCKeyPackage(object): dates = (data.get(key + '.sw', None), data.get(key + '.hw', None)) dates = [x for x in dates if x is not None] if dates: - out['ipatoken' + key] = unicode(reducer(dates).strftime("%Y%m%d%H%M%SZ")) + out['ipatoken' + key] = unicode(ipautil.datetime_to_ldap_gentime(reducer(dates))) class PSKCDocument(object): -- 2.5.0
-- 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