937546
From 5731aa2850d150a90ad84ce5492cd5d8b154e413 Mon Sep 17 00:00:00 2001
937546
From: Florence Blanc-Renaud <flo@redhat.com>
937546
Date: Tue, 23 Jul 2019 09:31:53 +0200
937546
Subject: [PATCH] user-stage: transfer all attributes from preserved to stage
937546
 user
937546
937546
The user-stage command is internally implemented as:
937546
- user_show(all=True) in order to read the user attributes
937546
- loop on the attributes defined as possible to add using stageuser-add and
937546
transform them into new options for stageuser_add (for instance stageuser-add
937546
provides the option --shell for the attribute loginshell, but there is no
937546
option for the attribute businesscategory).
937546
- call stageuser_add in order to create a new entry in the active users subtree
937546
- user-del to remove the previous entry in the staged users subtree
937546
937546
The issue is in the 2nd step. Only the attributes with a stageuser-add option
937546
are processed.
937546
The logic of the code should be slightly modified, so that all the attributes
937546
read in the first step are processed:
937546
- if they correspond to an option of stageuser-add, process them like it's
937546
currently done. For instance if the entry contains displayname, then it
937546
should be processed as --displayName=value in the stageuser-add cmd
937546
- if they do not correspond to an option of stageuser-add, add them with
937546
--setattr=<attrname>=<attrvalue>
937546
937546
Note that some attributes may need to be filtered, for instance user-show
937546
returns has_password or has_keytab, which do not correspond to attributes
937546
in the LDAP entry.
937546
937546
Fixes: https://pagure.io/freeipa/issue/7597
937546
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
937546
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
937546
---
937546
 ipaserver/plugins/user.py | 44 +++++++++++++++++++++++++++++++++++++++
937546
 1 file changed, 44 insertions(+)
937546
937546
diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py
937546
index 980385dc83e93ec4a65726077b34917e21115efa..fbf7b11789c58377366f187211c4e403d0cf7ffe 100644
937546
--- a/ipaserver/plugins/user.py
937546
+++ b/ipaserver/plugins/user.py
937546
@@ -919,7 +919,29 @@ class user_stage(LDAPMultiQuery):
937546
     has_output = output.standard_multi_delete
937546
     msg_summary = _('Staged user account "%(value)s"')
937546
 
937546
+    # when moving from preserved to stage, some attributes may be
937546
+    # present in the preserved entry but cannot be provided to
937546
+    # stageuser_add
937546
+    # For instance: dn and uid are derived from LOGIN argument
937546
+    #    has_keytab, has_password, preserved are virtual attributes
937546
+    #    ipauniqueid, krbcanonicalname, sshpubkeyfp, krbextradata
937546
+    #    are automatically generated
937546
+    #    ipacertmapdata can only be provided with user_add_certmapdata
937546
+    ignore_attrs = [u'dn', u'uid',
937546
+                    u'has_keytab', u'has_password', u'preserved',
937546
+                    u'ipauniqueid', u'krbcanonicalname',
937546
+                    u'sshpubkeyfp', u'krbextradata',
937546
+                    u'ipacertmapdata',
937546
+                    u'nsaccountlock']
937546
+
937546
     def execute(self, *keys, **options):
937546
+
937546
+        def _build_setattr_arg(key, val):
937546
+            if isinstance(val, bytes):
937546
+                return u"{}={}".format(key, val.decode('UTF-8'))
937546
+            else:
937546
+                return u"{}={}".format(key, val)
937546
+
937546
         staged = []
937546
         failed = []
937546
 
937546
@@ -940,8 +962,30 @@ class user_stage(LDAPMultiQuery):
937546
                     value = value[0]
937546
                 new_options[param.name] = value
937546
 
937546
+            # Some attributes may not be accessible through the Command
937546
+            # options and need to be added with --setattr
937546
+            set_attr = []
937546
+            for userkey in user.keys():
937546
+                if userkey in new_options or userkey in self.ignore_attrs:
937546
+                    continue
937546
+                value = user[userkey]
937546
+
937546
+                if isinstance(value, (list, tuple)):
937546
+                    for val in value:
937546
+                        set_attr.append(_build_setattr_arg(userkey, val))
937546
+                else:
937546
+                    set_attr.append(_build_setattr_arg(userkey, val))
937546
+            if set_attr:
937546
+                new_options[u'setattr'] = set_attr
937546
+
937546
             try:
937546
                 self.api.Command.stageuser_add(*single_keys, **new_options)
937546
+                # special handling for certmapdata
937546
+                certmapdata = user.get(u'ipacertmapdata')
937546
+                if certmapdata:
937546
+                    self.api.Command.stageuser_add_certmapdata(
937546
+                        *single_keys,
937546
+                        ipacertmapdata=certmapdata)
937546
                 try:
937546
                     self.api.Command.user_del(*multi_keys, preserve=False)
937546
                 except errors.ExecutionError:
937546
-- 
937546
2.20.1
937546