Skip to content

Commit

Permalink
Fix parsing of PPolicyControl ASN.1 structure
Browse files Browse the repository at this point in the history
Password policy control decoder failed to handle graceAuthNsRemaining
correctly. The warning.getComponentByName('timeBeforeExpiration') call
materialized the time before expiration CHOICE element. The fixed
implementation uses pyasn1's dict interface to check which CHOICE
element is set.

https://github.com/python-ldap/python-ldap/pull/194
Closes: https://github.com/python-ldap/python-ldap/issues/192
See: https://github.com/python-ldap/python-ldap/issues/193
Signed-off-by: Christian Heimes <cheimes@redhat.com>
  • Loading branch information
Christian Heimes authored and Petr Viktorin committed Mar 27, 2018
1 parent f477486 commit 4a6a719
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 19 deletions.
35 changes: 16 additions & 19 deletions Lib/ldap/controls/ppolicy.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
]

# Imports from python-ldap 2.4+
import ldap.controls
from ldap.controls import RequestControl,ResponseControl,ValueLessRequestControl,KNOWN_RESPONSE_CONTROLS
from ldap.controls import (
ResponseControl, ValueLessRequestControl, KNOWN_RESPONSE_CONTROLS
)

# Imports from pyasn1
from pyasn1.type import tag,namedtype,namedval,univ,constraint
from pyasn1.codec.ber import encoder,decoder
from pyasn1_modules.rfc2251 import LDAPDN
from pyasn1.codec.der import decoder


class PasswordPolicyWarning(univ.Choice):
Expand Down Expand Up @@ -70,25 +70,22 @@ def __init__(self,criticality=False):

def decodeControlValue(self,encodedControlValue):
ppolicyValue,_ = decoder.decode(encodedControlValue,asn1Spec=PasswordPolicyResponseValue())
self.timeBeforeExpiration = None
self.graceAuthNsRemaining = None
self.error = None

warning = ppolicyValue.getComponentByName('warning')
if not warning.hasValue():
self.timeBeforeExpiration,self.graceAuthNsRemaining = None,None
else:
timeBeforeExpiration = warning.getComponentByName('timeBeforeExpiration')
if timeBeforeExpiration.hasValue():
self.timeBeforeExpiration = int(timeBeforeExpiration)
else:
self.timeBeforeExpiration = None
graceAuthNsRemaining = warning.getComponentByName('graceAuthNsRemaining')
if graceAuthNsRemaining.hasValue():
self.graceAuthNsRemaining = int(graceAuthNsRemaining)
else:
self.graceAuthNsRemaining = None
if warning.hasValue():
if 'timeBeforeExpiration' in warning:
self.timeBeforeExpiration = int(
warning.getComponentByName('timeBeforeExpiration'))
if 'graceAuthNsRemaining' in warning:
self.graceAuthNsRemaining = int(
warning.getComponentByName('graceAuthNsRemaining'))

error = ppolicyValue.getComponentByName('error')
if error.hasValue():
self.error = int(error)
else:
self.error = None


KNOWN_RESPONSE_CONTROLS[PasswordPolicyControl.controlType] = PasswordPolicyControl
33 changes: 33 additions & 0 deletions Tests/t_ldap_controls_ppolicy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import os
import unittest

# Switch off processing .ldaprc or ldap.conf before importing _ldap
os.environ['LDAPNOINIT'] = '1'

from ldap.controls import ppolicy


PP_GRACEAUTH = b'0\x84\x00\x00\x00\t\xa0\x84\x00\x00\x00\x03\x81\x01\x02'
PP_TIMEBEFORE = b'0\x84\x00\x00\x00\t\xa0\x84\x00\x00\x00\x03\x80\x012'


class TestControlsPPolicy(unittest.TestCase):
def assertPPolicy(self, pp, timeBeforeExpiration=None,
graceAuthNsRemaining=None, error=None):
self.assertEqual(pp.timeBeforeExpiration, timeBeforeExpiration)
self.assertEqual(pp.graceAuthNsRemaining, graceAuthNsRemaining)
self.assertEqual(pp.error, error)

def test_ppolicy_graceauth(self):
pp = ppolicy.PasswordPolicyControl()
pp.decodeControlValue(PP_GRACEAUTH)
self.assertPPolicy(pp, graceAuthNsRemaining=2)

def test_ppolicy_timebefore(self):
pp = ppolicy.PasswordPolicyControl()
pp.decodeControlValue(PP_TIMEBEFORE)
self.assertPPolicy(pp, timeBeforeExpiration=50)


if __name__ == '__main__':
unittest.main()

0 comments on commit 4a6a719

Please sign in to comment.