Skip to content

Commit

Permalink
support more DateTime attributes in LDAP searches in IPA API
Browse files Browse the repository at this point in the history
LDAPSearch class constructs a filter from a set of attributes and their
values passed in by the command. During this construction process a
limited set of attributes gets converted to a special form, the rest is
simply taken as a string and escaped according to LDAP rules.

This means DateTime class would simply be converted to string using
str(DateTime) and that uses default formatting method. For LDAP we need
to apply a specific formatting method instead.

Following LDAP attributes now handled as datetime.datetime:

 ( 1.3.6.1.4.1.5322.21.2.5 NAME 'krbLastAdminUnlock' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE)
 ( 2.16.840.1.113719.1.301.4.6.1 NAME 'krbPrincipalExpiration' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE)
 ( 2.16.840.1.113719.1.301.4.37.1 NAME 'krbPasswordExpiration' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE)
 ( 2.16.840.1.113719.1.301.4.45.1 NAME 'krbLastPwdChange' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE)
 ( 2.16.840.1.113719.1.301.4.48.1 NAME 'krbLastSuccessfulAuth' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE)
 ( 2.16.840.1.113719.1.301.4.49.1 NAME 'krbLastFailedAuth' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE)
 ( 2.16.840.1.113730.3.8.16.1.3  NAME 'ipatokenNotBefore' DESC 'Token validity date' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE X-ORIGIN 'IPA OTP')
 ( 2.16.840.1.113730.3.8.16.1.4  NAME 'ipatokenNotAfter' DESC 'Token expiration date' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE X-ORIGIN 'IPA OTP')

Fixes: https://pagure.io/freeipa/issue/9395

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Antonio Torres <antorres@redhat.com>
  • Loading branch information
abbra authored and antoniotorresm committed Aug 21, 2023
1 parent d5ae5e1 commit ef955c9
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 5 deletions.
22 changes: 17 additions & 5 deletions ipapython/ipaldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import errno
import logging
import time
import datetime
from datetime import datetime
from decimal import Decimal
from copy import deepcopy
import contextlib
Expand Down Expand Up @@ -689,11 +689,12 @@ class LDAPClient:
'1.3.6.1.4.1.1466.115.121.1.10' : bytes, # Certificate Pair
'1.3.6.1.4.1.1466.115.121.1.12' : DN, # Distinguished Name
'1.3.6.1.4.1.1466.115.121.1.23' : bytes, # Fax
'1.3.6.1.4.1.1466.115.121.1.24' : datetime.datetime,
'1.3.6.1.4.1.1466.115.121.1.24' : datetime, # GeneralizedTime
'1.3.6.1.4.1.1466.115.121.1.28' : bytes, # JPEG
'1.3.6.1.4.1.1466.115.121.1.40' : bytes, # OctetString (same as Binary)
'1.3.6.1.4.1.1466.115.121.1.49' : bytes, # Supported Algorithm
'1.3.6.1.4.1.1466.115.121.1.51' : bytes, # Teletext Terminal Identifier
'1.3.6.1.4.1.5322.21.2.5' : datetime, # krbLastAdminUnlock

'2.16.840.1.113730.3.8.3.3' : DN, # enrolledBy
'2.16.840.1.113730.3.8.3.18' : DN, # managedBy
Expand All @@ -706,16 +707,23 @@ class LDAPClient:
'2.16.840.1.113730.3.8.7.1' : DN, # memberAllowCmd
'2.16.840.1.113730.3.8.7.2' : DN, # memberDenyCmd

'2.16.840.1.113719.1.301.4.6.1' : datetime, # krbPrincipalExpiration
'2.16.840.1.113719.1.301.4.14.1' : DN, # krbRealmReferences
'2.16.840.1.113719.1.301.4.17.1' : DN, # krbKdcServers
'2.16.840.1.113719.1.301.4.18.1' : DN, # krbPwdServers
'2.16.840.1.113719.1.301.4.26.1' : DN, # krbPrincipalReferences
'2.16.840.1.113719.1.301.4.29.1' : DN, # krbAdmServers
'2.16.840.1.113719.1.301.4.36.1' : DN, # krbPwdPolicyReference
'2.16.840.1.113719.1.301.4.37.1' : datetime, # krbPasswordExpiration
'2.16.840.1.113719.1.301.4.40.1' : DN, # krbTicketPolicyReference
'2.16.840.1.113719.1.301.4.41.1' : DN, # krbSubTrees
'2.16.840.1.113719.1.301.4.45.1' : datetime, # krbLastPwdChange
'2.16.840.1.113719.1.301.4.48.1' : datetime, # krbLastSuccessfulAuth
'2.16.840.1.113719.1.301.4.49.1' : datetime, # krbLastFailedAuth
'2.16.840.1.113719.1.301.4.52.1' : DN, # krbObjectReferences
'2.16.840.1.113719.1.301.4.53.1' : DN, # krbPrincContainerRef
'2.16.840.1.113730.3.8.16.1.3' : datetime, # ipatokenNotBefore
'2.16.840.1.113730.3.8.16.1.4' : datetime, # ipatokenNotAfter
}

# In most cases we lookup the syntax from the schema returned by
Expand Down Expand Up @@ -990,7 +998,7 @@ def encode(self, val):
# key in dict must be str not bytes
dct = dict((k, self.encode(v)) for k, v in val.items())
return dct
elif isinstance(val, datetime.datetime):
elif isinstance(val, datetime):
return val.strftime(LDAP_GENERALIZED_TIME_FORMAT).encode('utf-8')
elif isinstance(val, crypto_x509.Certificate):
return val.public_bytes(x509.Encoding.DER)
Expand All @@ -1012,8 +1020,8 @@ def decode(self, val, attr):
return val.decode('utf-8')
elif target_type is bool:
return val.decode('utf-8') == 'TRUE'
elif target_type is datetime.datetime:
return datetime.datetime.strptime(
elif target_type is datetime:
return datetime.strptime(
val.decode('utf-8'), LDAP_GENERALIZED_TIME_FORMAT)
elif target_type is DNSName:
return DNSName.from_text(val.decode('utf-8'))
Expand Down Expand Up @@ -1372,6 +1380,10 @@ def make_filter_from_attr(
# value[-2:0] is empty string for the initial '\\'
value = u'\\'.join(
value[i:i+2] for i in six.moves.range(-2, len(value), 2))
elif isinstance(value, datetime):
value = value.strftime(
LDAP_GENERALIZED_TIME_FORMAT)
value = ldap.filter.escape_filter_chars(value)
else:
value = str(value)
value = ldap.filter.escape_filter_chars(value)
Expand Down
23 changes: 23 additions & 0 deletions ipatests/test_ipaserver/test_ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

from __future__ import absolute_import

from datetime import datetime, timedelta
import os
import sys

Expand Down Expand Up @@ -140,6 +141,28 @@ def test_autobind(self):
cert = entry_attrs.get('usercertificate')[0]
assert cert.serial_number is not None

def test_generalized_time(self):
"""
Test that LDAP generalized time is converted to/from datetime
"""
self.conn = ldap2(api)
try:
self.conn.connect(autobind=True)
except errors.ACIError:
pytest.skip("Only executed as root")
if not api.Backend.rpcclient.isconnected():
api.Backend.rpcclient.connect()
newdate = datetime.now() + timedelta(days=365)
lastdate = api.Backend.ldap2.encode(newdate).decode('utf-8')
api.Command["user_mod"](
"admin",
**dict(setattr=("krbprincipalexpiration=%s" % lastdate))
)
result = api.Command["user_find"](
**dict(krbprincipalexpiration=lastdate)
)
assert result['count'] == 1


@pytest.mark.tier0
@pytest.mark.needs_ipaapi
Expand Down

0 comments on commit ef955c9

Please sign in to comment.