Univention Bugzilla – Bug 41207
objectClass is not removed from object when extended attribute wants it
Last modified: 2016-09-29 20:48:44 CEST
On the Tab 'LDAP mapping' within LDAP/Extended Attributes, there is a Checkbox labeled 'Remove object class if the attribute is removed'. When it's checked and the Attribute is cleared/removed, the ObjectClass remains at the Object itself. Happened here Ticket #2016050321000407
This is Bug #15841 again, which was tagged WONTFIX. FYI: Removing the OC only works for boolean EAs.
(In reply to Philipp Hahn from comment #1) > This is Bug #15841 again, which was tagged WONTFIX. > FYI: Removing the OC only works for boolean EAs. Bug #15841 was filed against UCS 2.4 and had been discarded due to vast changes in newer Versions. However this issue is still present in UCS 4.1 so it had been cloned to fit the adopted conditions.
(In reply to Philipp Hahn from comment #1) > FYI: Removing the OC only works for boolean EAs. The expected result would be that it also works for other extended attributes, wouldn't it?
Assuming we have the following schema: objectClass foo MAY (foo1, foo2, foo3, foo4) objectClass bar MAY (bar1, bar2, bar3, bar4) And the following UDM module/handler: property_descriptions = [ foo1, foo2, bar1, bar3, ] extended_attributes = [{ objectClass = bar, attribute = bar2, removeObjectClassWhenRemovingAttribute = True }] And the LDAP might contain an object like: DN: cn=test objectClass: foo objectClass: bar foo1: 'hi' foo2: 'blub' foo3: 'blah' bar1: 'test' bar2: 'ext.attr' bar3: 'asdf' bar4: 'fouh' When I now want to --remove=bar2 the code cannot remove the object class 'bar' because the attribute bar1 is still set (which is defined in UDM) and the attribute bar4 is also set (which exists at the LDAP object but is not even mapped in the UDM handler). To fix this bug I need to parse the Schema (by reading and parsing cn=Subschema). Then I need to get the final modlist (ml) and merge it with all currently set values (self.oldattr). Then I can check if any attribute which is used by that object class is still used. If not, the object class can be removed. Otherwise it must be kept to prevent e.g. "LDAP Error: No such attribute: modify/delete: oxDisplayName: no such attribute".
Let's start with a simple solution without parsing the LDAP schema. If one sets removeObjectClassWhenRemovingAttributs flag and the objectClass is still used, an error message would be OK.
(In reply to Stefan Gohmann from comment #5) > Let's start with a simple solution without parsing the LDAP schema. If one > sets removeObjectClassWhenRemovingAttributs flag and the objectClass is > still used, an error message would be OK. This will break OX as all extended attributes from OX define univentionUDMPropertyDeleteObjectClass=1 which will remove the object class if any of those values is empty (has no default value or OX was installed after the user was created). It would be this patch: diff --git a/management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py b/management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py index 9a2ed9e..e71b505 100644 --- a/management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py +++ b/management/univention-directory-manager-modules/modules/univention/admin/handlers/__init__.py @@ -951 +951 @@ def _modify(self, modify_childs=1, ignore_license=0): - if prop.deleteObjClass == '1' and prop.name not in self.info: + if prop.deleteObjClass and prop.name not in self.info:
(In reply to Florian Best from comment #6) > (In reply to Stefan Gohmann from comment #5) > > Let's start with a simple solution without parsing the LDAP schema. If one > > sets removeObjectClassWhenRemovingAttributs flag and the objectClass is > > still used, an error message would be OK. > This will break OX as all extended attributes from OX define > univentionUDMPropertyDeleteObjectClass=1 which will remove the object class > if any of those values is empty (has no default value or OX was installed > after the user was created). That's a valid and important point.
*** Bug 15841 has been marked as a duplicate of this bug. ***
Created attachment 7693 [details] test_object_classes.py Added a test case which checks various valid and invalid combinations. @Philipp, etc.: Do you come up with more combinations?
Created attachment 7694 [details] patch First patch. I hope I can further cleanup the patch, the code looks a little bit complex. The udm-users tests pass.
In the logfiles I can see that the patch successfully prevents to delete some invalid combinations: The attribute 'surname' is required in the current object classes. The attribute 'commonName' is required in the current object classes. The attribute 'userid' is required in the current object classes.
univention-directory-manager-modules (11.0.3-1): r69589 | Bug #41207: reenable object class removal for extended attributes univention-directory-manager-modules.yaml: r69590 | YAML Bug #41207
RFC: handlers/__init__.py:806 > schema = ldap.schema.SubSchema(self.lo.lo.lo.read_subschemasubentry_s(self.lo.lo.lo.search_subschemasubentry_s()), 0) every _modify() will now require two additional *synchronous* requests to the LDAP server to find and fetch the LDAP schema. $ time ./create-32k-users-in-groups -n 1000 $ time (base=$(ucr get ldap/base);now=$(date +%s);for ((i=0;i<1000;i+=1)); do udm users/user modify --dn "$(printf 'uid=nscd%04x,cn=users,%s' $i "$base")" --set description="$now";done) # original unpatched version real 4m25.033s user 2m51.572s sys 0m5.172s real 1m44.533s user 0m30.616s sys 0m6.440s # your patched version real 4m20.282s user 2m52.492s sys 0m5.096s real 5m50.531s user 0m31.692s sys 0m6.780s Either cache it or limit it to the case when objectClass is modified (you already check that in line 801) > if set(self.oldattr.get('objectClass', [])) != ocs:
Valid point! The schema is now cached in univention.uldap.access() and dropped if the connection re-establishes (as the schema might be updated then). univention-python (9.0.1-3): r70051 | Bug #41207: autopep8 r70050 | Bug #41207: code cleanup r70049 | Bug #41207: add access.get_schema() univention-python.yaml: r70052 | YAML Bug #41207 univention-directory-manager-modules (11.0.3-5): r70048 | Bug #41207: cache schema
OK: Performance is okay again real 4m18.561s user 2m50.440s sys 0m4.972s real 1m45.837s user 0m30.928s sys 0m6.400s
*** Bug 41530 has been marked as a duplicate of this bug. ***
FORK: Bug #21608 2): currently the objectClass associated with an Extended Option can't be removed, because UDM has no logic to parse the "objectClass"es on load and to enable the associated options. That only works if at least one "attribute" of that objectClass is loaded. Thus neither UDM-UMC nor udm-cli show the option as being enabled after loading. Thus the option can't be deselected, thus the objectClass is not removed. FAIL: LDAP-Schema-handling is incomplete due to multiple-alias-names-per-attribute: # ldapsearch -LLLo ldif-wrap=no -x -b cn=Subschema -s base attributeTypes objectClasses | less # univention-ldapsearch -LLLb cn=bqwds365ti,cn=groups,dc=phahn,dc=qa objectClass structuralObjectClass dn: cn=bqwds365ti,cn=groups,dc=phahn,dc=qa objectClass: posixGroup objectClass: sambaGroupMapping objectClass: top objectClass: univentionGroup objectClass: univentionFreeAttributes objectClass: univentionObject structuralObjectClass: posixGroup # ldapsearch -LLLo ldif-wrap=no -x -b cn=Subschema -s base objectClasses | grep posixGroup objectClasses: ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Abstraction of a group of accounts' SUP top STRUCTURAL MUST ( cn $ gidNumber ) MAY ( userPassword $ memberUid $ description ) ) # ldapsearch -LLLo ldif-wrap=no -x -b cn=Subschema -s base attributeTypes | grep --word cn dn: cn=Subschema attributeTypes: ( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC4519: common name(s) for which the entity is known by' SUP name ) self.oldattr() only contains 'cn', but not 'commonName'; or vis versa. Patch follows. FYI: There's a 2nd issue when two EAs are defined using the same OC, but only one using an option. In that case removing the dependent EA also removed the non-dependent EA. This is not nice, but IMHO preferable to only one EA being removed, while the 2nd EA survives and the EO is shown again next time, as one of the EAs still exists. OK: r70051 r70050 r70049 r70048 OK: dpkg-query -W python-univention-directory-manager # 11.0.3-10.1402.201606141456 OK: dpkg-query -W python-univention # 9.0.1-3.161.201606091857 OK: errata-announce -V --only univention-directory-manager-modules.yaml OK: univention-directory-manager-modules.yaml OK: errata-announce -V --only univention-python.yaml FIXED: univention-python.yaml r70191 | Bug #41207 QA: Fix YAML
Created attachment 7746 [details] Fix multiple-alias-names-per-attribute First check newattr for allowed attributes. Then check MUST attributes. Return early from function to simplify nested logic.
ucs-test: r70218 | Bug #41207 test: Add tests for EA/EO removal r70217 | Bug #25240, et al: test: Fix UDM-CLI building r70216 | Bug #25240, et al: test Print UDM-CLI command r70215 | Bug #25240, et al: ucs-test autopep8
Let's release the changes as is - it doesn't break anything comparing to before. The continued fix will be done at Bug #41580.
<http://errata.software-univention.de/ucs/4.1/198.html> <http://errata.software-univention.de/ucs/4.1/199.html>