URL: https://github.com/freeipa/freeipa/pull/5720
Author: flo-renaud
 Title: #5720: [Backport][ipa-4-9] Retrieve the user objectclasses when 
checking for existence
Action: opened

PR body:
"""
This PR was opened automatically because PR #5707 was pushed to master and 
backport to ipa-4-9 is required.
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/5720/head:pr5720
git checkout pr5720
From 495a6ed7e9833698f801bd66f84facc59e90cb1e Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Tue, 2 Mar 2021 15:11:18 -0500
Subject: [PATCH] Retrieve the user objectclasses when checking for existence

This saves at least one search per user-mod because the current
set of objectclasses are verified to ensure they are complete
on each update.

So always retrieve them in get_either_dn(). They are used by
every call but there is negligible overhead in retrieving
this from LDAP.

https://pagure.io/freeipa/issue/8801

Signed-off-by: Rob Crittenden <rcrit...@redhat.com>
---
 ipaserver/plugins/user.py | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py
index 775eb6346eb..6f7facb5380 100644
--- a/ipaserver/plugins/user.py
+++ b/ipaserver/plugins/user.py
@@ -443,15 +443,16 @@ def get_delete_dn(self, *keys, **options):
 
     def get_either_dn(self, *keys, **options):
         '''
-        Returns the DN of a user
+        Returns the DN of a user and their objectclasses
         The user can be active (active container) or delete (delete container)
         If the user does not exist, returns the Active user DN
         '''
         ldap = self.backend
+        oc = []
         # Check that this value is a Active user
         try:
             active_dn = self.get_dn(*keys, **options)
-            ldap.get_entry(active_dn, ['dn'])
+            oc = ldap.get_entry(active_dn, ['dn', 'objectclass'])['objectclass']
 
             # The Active user exists
             dn = active_dn
@@ -459,7 +460,9 @@ def get_either_dn(self, *keys, **options):
             # Check that this value is a Delete user
             delete_dn = self.get_delete_dn(*keys, **options)
             try:
-                ldap.get_entry(delete_dn, ['dn'])
+                oc = ldap.get_entry(
+                    delete_dn, ['dn', 'objectclass']
+                )['objectclass']
 
                 # The Delete user exists
                 dn = delete_dn
@@ -467,7 +470,7 @@ def get_either_dn(self, *keys, **options):
                 # The user is neither Active/Delete -> returns that Active DN
                 dn = active_dn
 
-        return dn
+        return dn, oc
 
     def _normalize_manager(self, manager):
         """
@@ -688,7 +691,7 @@ class user_del(baseuser_del):
     def _preserve_user(self, pkey, delete_container, **options):
         assert isinstance(delete_container, DN)
 
-        dn = self.obj.get_either_dn(pkey, **options)
+        dn, _oc = self.obj.get_either_dn(pkey, **options)
         delete_dn = DN(dn[0], delete_container)
         ldap = self.obj.backend
         logger.debug("preserve move %s -> %s", dn, delete_dn)
@@ -744,7 +747,7 @@ def _preserve_user(self, pkey, delete_container, **options):
             self._exc_wrapper(pkey, options, ldap.update_entry)(entry_attrs)
 
     def pre_callback(self, ldap, dn, *keys, **options):
-        dn = self.obj.get_either_dn(*keys, **options)
+        dn, _oc = self.obj.get_either_dn(*keys, **options)
 
         # For User life Cycle: user-del is a common plugin
         # command to delete active user (active container) and
@@ -819,7 +822,9 @@ def get_options(self):
             yield option
 
     def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
-        dn = self.obj.get_either_dn(*keys, **options)
+        dn, oc = self.obj.get_either_dn(*keys, **options)
+        if 'objectclass' not in entry_attrs and 'rename' not in options:
+            entry_attrs.update({'objectclass': oc})
         self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys,
                                  **options)
         validate_nsaccountlock(entry_attrs)
@@ -901,7 +906,7 @@ class user_show(baseuser_show):
     )
 
     def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
-        dn = self.obj.get_either_dn(*keys, **options)
+        dn, _oc = self.obj.get_either_dn(*keys, **options)
         self.pre_common_callback(ldap, dn, attrs_list, *keys, **options)
         return dn
 
@@ -923,7 +928,7 @@ def execute(self, *keys, **options):
         ldap = self.obj.backend
 
         # First check that the user exists and is a delete one
-        delete_dn = self.obj.get_either_dn(*keys, **options)
+        delete_dn, _oc = self.obj.get_either_dn(*keys, **options)
         try:
             self._exc_wrapper(keys, options, ldap.get_entry)(delete_dn)
         except errors.NotFound:
@@ -1063,7 +1068,7 @@ def execute(self, *keys, **options):
 
         check_protected_member(keys[-1])
 
-        dn = self.obj.get_either_dn(*keys, **options)
+        dn, _oc = self.obj.get_either_dn(*keys, **options)
         ldap.deactivate_entry(dn)
 
         return dict(
@@ -1083,7 +1088,7 @@ class user_enable(LDAPQuery):
     def execute(self, *keys, **options):
         ldap = self.obj.backend
 
-        dn = self.obj.get_either_dn(*keys, **options)
+        dn, _oc = self.obj.get_either_dn(*keys, **options)
 
         ldap.activate_entry(dn)
 
@@ -1107,7 +1112,7 @@ class user_unlock(LDAPQuery):
     msg_summary = _('Unlocked account "%(value)s"')
 
     def execute(self, *keys, **options):
-        dn = self.obj.get_either_dn(*keys, **options)
+        dn, _oc = self.obj.get_either_dn(*keys, **options)
         entry = self.obj.backend.get_entry(
             dn, ['krbLastAdminUnlock', 'krbLoginFailedCount'])
 
@@ -1191,7 +1196,7 @@ def get_args(self):
 
     def execute(self, *keys, **options):
         ldap = self.obj.backend
-        dn = self.api.Object.user.get_either_dn(*keys, **options)
+        dn, _oc = self.api.Object.user.get_either_dn(*keys, **options)
         attr_list = ['krbloginfailedcount', 'krblastsuccessfulauth', 'krblastfailedauth', 'nsaccountlock']
 
         disabled = False
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/freeipa-devel@lists.fedorahosted.org
Do not reply to spam on the list, report it: 
https://pagure.io/fedora-infrastructure

Reply via email to