Bug 1658302

Summary: ipaldap: invalid modlist when attribute encoding can vary
Product: Red Hat Enterprise Linux 8 Reporter: Thomas Woerner <twoerner>
Component: ipaAssignee: IPA Maintainers <ipa-maint>
Status: CLOSED CURRENTRELEASE QA Contact: Kaleem <ksiddiqu>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 8.0CC: abokovoy, amore, ftweedal, ksiddiqu, pvoborni, rcritten, tscherf
Target Milestone: rc   
Target Release: 8.0   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2019-06-14 01:44:10 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Thomas Woerner 2018-12-11 17:27:22 UTC
This bug is created as a clone of upstream ticket:
https://pagure.io/freeipa/issue/7750

ipaldap does not take into account the possibility of the attribute encoding
as returned by 389DS differing from the attribute encoding produced by FreeIPA.
This can occur especially in DNs that require escpaing of special characters.
For example, 389DS escapes special characters using hex encoding:

CN=Test Sub-CA 201604041620,OU=ftweedal,O=Red Hat\2C Inc.,L=Brisbane,C=AU

Whereas FreeIPA escapes the character directly.

CN=Test Sub-CA 201604041620,OU=ftweedal,O=Red Hat\, Inc.,L=Brisbane,C=AU

Therefore it is possible to generate an invalid modlist. For example, during
external CA certificate renewal, if the issuer DN includes a comma in one of the
attribute values (as above), an invalid modlist will be generated:

[ (ldap.MOD_ADD, 'ipacaissuerdn', [b'CN=Test Sub-CA 201604041620,OU=ftweedal,O=Red Hat\, Inc.,L=Brisbane,C=AU'])
, (ldap.MOD_DELETE, 'ipacaissuerdn', [b'CN=Test Sub-CA 201604041620,OU=ftweedal,O=Red Hat\2C Inc.,L=Brisbane,C=AU'])
]

In the above case, the attribute already exists, and LDAP error 20 (attributeOrValueExists)
occurs.

Comment 3 Fraser Tweedale 2019-01-02 04:43:28 UTC
Kaleem,

To verify this bug, follow the transcript below.

1) On the server, kinit (the user doesn't really matter)

  [f29-0:~] ftweedal% kinit admin
  Password for admin: XXXXXXXX


2) Fire up the python REPL and initialise the API
 
  [f29-0:~] ftweedal% python3
  Python 3.7.1 (default, Nov 23 2018, 10:01:49)
  [GCC 8.2.1 20181105 (Red Hat 8.2.1-5)] on linux
  Type "help", "copyright", "credits" or "license" for more information.
  >>> from ipalib import api
  >>> api.bootstrap(context='cli', in_server=True)
  ipa: ERROR: Cannot open log file '/var/log/ipa/cli.log': [Errno 13] Permission denied: '/var/log/ipa/cli.log'                                                                  
  >>> api.finalize()


3) Connect LDAP and create an LDAPEntry object.  We are not actually going to
   add the entry to the database; we just need it to test the modlist generation.

>>> api.Backend.ldap2.connect()
>>> from ipapython.ipaldap import LDAPEntry
>>> from ipapython.dn import DN
>>> entry = LDAPEntry(api.Backend.ldap2, DN('cn=fake'), cn='fake')


4) Add an attribute that uses distinguished name syntax.  We assign a
   RAW value, using a serialisation that DIFFERS from what the
   ipapython.dn.DN type would produce.

>>> entry.raw['distinguishedName'] = [b'O=Red Hat\\2C Inc.']


5) Trick the entry into believing that that value was part of the original
   data we received from LDAP.

>>> entry.reset_modlist()


6) Assign the distinguishedName value back onto itself.

>>> entry['distinguishedName'] = [entry['distinguishedName'][0]]


7) Generate the modlist.  We expect to see a delete, and an add.  The values are in fact
   equal, but have different serialisations.  The delete (represented by '1')
   MUST COME BEFORE the add (represented by '0').

>>> entry.generate_modlist()
[(1, 'distinguishedName', [b'O=Red Hat\\2C Inc.']), (0, 'distinguishedName', [b'O=Red Hat\\, Inc.'])]


Possible outcomes:

- If the output is as above, fix is verified.

- If the add (operation '0') precedes the delete ('1'), fail QA.

- If you get anything else, please needinfo me for further clarification.

HTH,
Fraser

Comment 4 anuja 2019-01-22 06:46:02 UTC
Verified using :
ipa-server-4.7.1-10.module+el8+2699+aa606a46.x86_64

Verified using Steps:

[root@vm-idm-001 ~]# kinit admin
Password for admin: 

[root@vm-idm-001 ~]# python3
Python 3.6.8 (default, Jan 11 2019, 02:17:16) 
[GCC 8.2.1 20180905 (Red Hat 8.2.1-3)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from ipalib import api
>>> api.bootstrap(context='cli', in_server=True)
>>> api.finalize()
>>> api.Backend.ldap2.connect()
>>> from ipapython.ipaldap import LDAPEntry
>>> from ipapython.dn import DN
>>> entry = LDAPEntry(api.Backend.ldap2, DN('cn=fake'), cn='fake')
>>> entry.raw['distinguishedName'] = [b'O=Red Hat\\2C Inc.']
>>> entry.reset_modlist()
>>> entry['distinguishedName'] = [entry['distinguishedName'][0]]
>>> entry.generate_modlist()
[(1, 'distinguishedName', [b'O=Red Hat\\2C Inc.']), (0, 'distinguishedName', [b'O=Red Hat\\, Inc.'])]
>>> 

Based on this marking bz as verified.