Univention Bugzilla – Bug 54347
On object creation return object's entryUUID
Last modified: 2022-02-02 16:05:14 CET
When creating an object using the UDM REST API the response should include the entryUUID of the object. This is required for adhoc federation use cases using a ldap federated Keycloak. The scope of this enhancement is limited to user objects, but it seems reasonable to have this also as a generic approach for all objects. But this might change the efforts on this request significantly.
(In reply to Thorsten from comment #0) > When creating an object using the UDM REST API the response should include > the entryUUID of the object. Should we really only return the entryUUID? Or will there be further requests in some weeks to also include something else? > This is required for adhoc federation use cases using a ldap federated > Keycloak. OK: the problem is a race condition between creation and fetching of the object?! In chat you wrote "multiple roundtrips cause sync problems with Keycloak LDAP federation". I don't understand that aspect yet. > The scope of this enhancement is limited to user objects, but it seems > reasonable to have this also as a generic approach for all objects. But this > might change the efforts on this request significantly. This doesn't change any effords - only doing it for user objects would be more efford. UDM is and should always a generic thing. From Bug #50252 comment 5: I disagree to implement that: We are currently only returning no representation after creating a object giving a Location header with a link where the object can be retrieved. So just follow that to receive the object representation including entryUUID! If we add the entryUUID (and all other properties?) we have to open the object again, do some calulations while it is most often not needed and decreases the performance especially for scenarios where we do a mass import of users. I don't know if significantly. A patch to achieve this only for entryUUID would be: diff --git management/univention-directory-manager-rest/src/univention/admin/rest/module.py management/univention-directory-manager-rest/src/univention/admin/rest/module.py index afdb35f162..9bbfac8626 100755 --- management/univention-directory-manager-rest/src/univention/admin/rest/module.py +++ management/univention-directory-manager-rest/src/univention/admin/rest/module.py @@ -2804,7 +2804,7 @@ class Object(FormBase, Resource): self.set_header('Location', self.urljoin(quote_dn(obj.dn))) self.set_status(201) self.add_caching(public=False, must_revalidate=True) - self.content_negotiation({}) + self.content_negotiation({'uuid': self.ldap_connection.getAttr(obj.dn, 'entryUUID')[0].decode('ASCII')}) return self.set_metadata(obj) Alternatively with PostReadControl (untested): diff --git management/univention-directory-manager-rest/src/univention/admin/rest/module.py management/univention-directory-manager-rest/src/univention/admin/rest/module.py index afdb35f162..4811dcd46b 100755 --- management/univention-directory-manager-rest/src/univention/admin/rest/module.py +++ management/univention-directory-manager-rest/src/univention/admin/rest/module.py @@ -2800,11 +2800,21 @@ class Object(FormBase, Resource): obj = yield self.pool.submit(module.get, dn) if not obj: - obj = yield self.create(object_type, dn) + from ldap.controls.readentry import PostReadControl + serverctrls = [PostReadControl(True, ['entryUUID'])] + response = {} + + obj = yield self.create(object_type, dn, serverctrls=serverctrls, response=response) self.set_header('Location', self.urljoin(quote_dn(obj.dn))) self.set_status(201) self.add_caching(public=False, must_revalidate=True) - self.content_negotiation({}) + + uuid = None + for c in response.get('ctrls', []): + if c.controlType == PostReadControl.controlType: + uuid = c.entry['entryUUID'][0].decode('ASCII') + + self.content_negotiation({'uuid': uuid}) return self.set_metadata(obj) @@ -2859,7 +2869,7 @@ class Object(FormBase, Resource): raise Finish() @tornado.gen.coroutine - def create(self, object_type, dn=None): + def create(self, object_type, dn=None, **kwargs): module = self.get_module(object_type) container = self.request.body_arguments['position'] superordinate = self.request.body_arguments['superordinate'] @@ -2884,7 +2894,7 @@ class Object(FormBase, Resource): if dn and not self.ldap_connection.compare_dn(dn, obj._ldap_dn()): self.raise_sanitization_error('dn', _('Trying to create an object with wrong RDN.')) - dn = yield self.pool.submit(self.handle_udm_errors, obj.create) + dn = yield self.pool.submit(self.handle_udm_errors, obj.create, **kwargs) raise tornado.gen.Return(obj) @tornado.gen.coroutine @@ -2894,12 +2904,12 @@ class Object(FormBase, Resource): yield self.pool.submit(self.handle_udm_errors, obj.modify) raise tornado.gen.Return(obj) - def handle_udm_errors(self, action): + def handle_udm_errors(self, action, *args, **kwargs): try: exists_msg = None error = None try: - return action() + return action(*args, **kwargs) except udm_errors.objectExists as exc: exists_msg = 'dn: %s' % (exc.args[0],) error = exc
The entryUUID (uuid) and DN (dn) has been added to the responses of object creations. We should not add any other information here in the future for performance reasons. univention-directory-manager-rest.yaml 9fcd42f02df7 | Bug #54347: return the entryUUID and DN after object creation univention-directory-manager-rest (10.0.2-5) 9fcd42f02df7 | Bug #54347: return the entryUUID and DN after object creation
Added another commit so that this can also be achieved via PUT: univention-directory-manager-rest (10.0.2-6) fefd6f05e86d | Bug #54347: fix creation of object via PUT request
Verified: * Code review; Ok * Package update: Ok * Function test: Ok * Before: root@primary20:~# curl -k -X POST -H "Accept: application/json" -H "Content-Type: application/json" https://Administrator:univention@localhost/univention/udm/users/user/ --data @1.json {"_links": {"curies": [{"name": "udm", "templated": true, "href": "https://localhost/univention/udm/relation/{rel}"}]}} * After: root@primary20:~# curl -k -X POST -H "Accept: application/json" -H "Content-Type: application/json" https://Administrator:univention@localhost/univention/udm/users/user/ --data @1.json {"dn": "uid=rest4,cn=users,dc=ucs50domain,dc=net", "uuid": "64501eca-0c8d-103c-9c46-8d8af8520506", "_links": {"curies": [{"name": "udm", "templated": true, "href": "https://localhost/univention/udm/relation/{rel}"}]}} * Advisory: Ok * 03374ae4ab | Minor wording adjustment
Also works for user creation via PUT: root@primary20:~# curl -k -X PUT \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ https://Administrator:univention@localhost/univention/udm/users/user/uid=rest7,cn=users,dc=ucs50domain,dc=net \ --data @user.json {"dn": "uid=rest7,cn=users,dc=ucs50domain,dc=net", "uuid": "b29872f6-0ca3-103c-9c70-8d8af8520506", "_links": {"curies": [{"name": "udm", "templated": true, "href": "https://localhost/univention/udm/relation/{rel}"}]}}
<https://errata.software-univention.de/#/?erratum=5.0x202>