[Freeipa-devel] [PATCH] change groupedit to perform operations on dn's for users

Kevin McCarthy kmccarth at redhat.com
Thu Sep 27 18:34:18 UTC 2007


This patch changes the groupedit.kid page to manipulate users using
their dns.  It adds proper escaping to the dynamically generated
javascript strings (at the python -> javascript) boundary don't fail if
they python variable contains a ' or "

Previously, the uids were being translated into dns using a search.  Now
the dns come directly from TG, so need to be translated into utf-8.

Next step is changing the page to work with groups too.

-Kevin

-------------- next part --------------
# HG changeset patch
# User Kevin McCarthy <kmccarth at redhat.com>
# Date 1190917653 25200
# Node ID d9bfdc313e9522daeaa5cfdcc9295da12190003d
# Parent  5bc5ed865060671057635f21456c561b4402416c
patch queue: group_users_use_dns.patch

diff -r 5bc5ed865060 -r d9bfdc313e95 ipa-server/ipa-gui/ipagui/controllers.py
--- a/ipa-server/ipa-gui/ipagui/controllers.py	Wed Sep 26 15:47:34 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/controllers.py	Thu Sep 27 11:27:33 2007 -0700
@@ -17,6 +17,7 @@ import ipa.config
 import ipa.config
 import ipa.ipaclient
 import ipa.user
+from ipa.entity import utf8_encode_values
 import xmlrpclib
 import forms.user
 import forms.group
@@ -534,12 +535,13 @@ class Root(controllers.RootController):
         #
         failed_adds = []
         try:
-            uidadds = kw.get('uidadd')
-            if uidadds != None:
-                if not(isinstance(uidadds,list) or isinstance(uidadds,tuple)):
-                    uidadds = [uidadds]
-                failed_adds = client.add_users_to_group(uidadds, kw.get('cn'))
-                kw['uidadd'] = failed_adds
+            dnadds = kw.get('dnadd')
+            if dnadds != None:
+                if not(isinstance(dnadds,list) or isinstance(dnadds,tuple)):
+                    dnadds = [dnadds]
+                failed_adds = client.add_members_to_group(
+                        utf8_encode_values(dnadds), kw.get('cn'))
+                kw['dnadd'] = failed_adds
         except ipaerror.IPAError, e:
             turbogears.flash("User update failed: " + str(e))
             return dict(form=group_edit_form, group=kw, members=member_dicts,
@@ -550,12 +552,13 @@ class Root(controllers.RootController):
         #
         failed_dels = []
         try:
-            uiddels = kw.get('uiddel')
-            if uiddels != None:
-                if not(isinstance(uiddels,list) or isinstance(uiddels,tuple)):
-                    uiddels = [uiddels]
-                failed_dels = client.remove_users_from_group(uiddels, kw.get('cn'))
-                kw['uiddel'] = failed_dels
+            dndels = kw.get('dndel')
+            if dndels != None:
+                if not(isinstance(dndels,list) or isinstance(dndels,tuple)):
+                    dndels = [dndels]
+                failed_dels = client.remove_members_from_group(
+                        utf8_encode_values(dndels), kw.get('cn'))
+                kw['dndel'] = failed_dels
         except ipaerror.IPAError, e:
             turbogears.flash("User update failed: " + str(e))
             return dict(form=group_edit_form, group=kw, members=member_dicts,
diff -r 5bc5ed865060 -r d9bfdc313e95 ipa-server/ipa-gui/ipagui/forms/group.py
--- a/ipa-server/ipa-gui/ipagui/forms/group.py	Wed Sep 26 15:47:34 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/forms/group.py	Thu Sep 27 11:27:33 2007 -0700
@@ -11,7 +11,7 @@ class GroupFields():
 
     group_orig = widgets.HiddenField(name="group_orig")
     member_data = widgets.HiddenField(name="member_data")
-    uid_to_cn_json = widgets.HiddenField(name="uid_to_cn_json")
+    dn_to_cn_json = widgets.HiddenField(name="dn_to_cn_json")
 
 class GroupNewValidator(validators.Schema):
     cn = validators.String(not_empty=True)
@@ -48,7 +48,7 @@ class GroupEditForm(widgets.Form):
     fields = [GroupFields.gidnumber, GroupFields.description,
               GroupFields.cn_hidden, GroupFields.editprotected_hidden,
               GroupFields.group_orig, GroupFields.member_data,
-              GroupFields.uid_to_cn_json]
+              GroupFields.dn_to_cn_json]
 
     validator = GroupEditValidator()
 
diff -r 5bc5ed865060 -r d9bfdc313e95 ipa-server/ipa-gui/ipagui/helpers/ipahelper.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ipa-server/ipa-gui/ipagui/helpers/ipahelper.py	Thu Sep 27 11:27:33 2007 -0700
@@ -0,0 +1,9 @@
+import re
+
+def javascript_string_escape(input):
+    """Escapes the ' " and \ characters in a string so
+       it can be embedded inside a dynamically generated string."""
+
+    return re.sub(r'[\'\"\\]',
+            lambda match: "\\%s" % match.group(),
+            input)
diff -r 5bc5ed865060 -r d9bfdc313e95 ipa-server/ipa-gui/ipagui/static/javascript/ipautil.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ipa-server/ipa-gui/ipagui/static/javascript/ipautil.js	Thu Sep 27 11:27:33 2007 -0700
@@ -0,0 +1,8 @@
+
+/*
+ * Escapes the ' " and \ characters in a string, so
+ * it can be embedded inside a dynamically generated string.
+ */
+function jsStringEscape(input) {
+    return input.gsub(/(['"\\])/, function(match){ return "\\" + match[0]} );
+}
diff -r 5bc5ed865060 -r d9bfdc313e95 ipa-server/ipa-gui/ipagui/templates/groupeditform.kid
--- a/ipa-server/ipa-gui/ipagui/templates/groupeditform.kid	Wed Sep 26 15:47:34 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/groupeditform.kid	Thu Sep 27 11:27:33 2007 -0700
@@ -3,21 +3,30 @@
   <form action="${action}" name="${name}" method="${method}" class="tableform"
       onsubmit="preSubmit()" >
 
+<?python
+from ipagui.helpers import ipahelper
+?>
+
 
   <?python searchurl = tg.url('/userlist_ajax') ?>
 
   <script type="text/javascript">
     // this is used for round-trip recontruction of the names.
-    // the hidden fields only contain uids.  
-    var uid_to_cn_hash = new Hash();
+    // the hidden fields only contain dns.
+    var dn_to_cn_hash = new Hash();
 
     // used to filter search results.
-    // records uids already in the group
+    // records dns already in the group
     var member_hash = new Hash();
 
     // used to prevent double adding
-    // records uid to be added
+    // records dns to be added
     var added_hash = new Hash();
+
+    // Tracks the div ids that each member belongs to.
+    // Since dn's will contain illegal characters for div ids, this is used
+    // to map them to the correct div
+    var dn_to_member_div_id = new Hash();
 
 
     function toggleProtectedFields(checkbox) {
@@ -38,32 +47,32 @@
       Element.remove(effect.element);
     }
 
-    function adduser(uid, cn) {
-      uid_to_cn_hash[uid] = cn;
-
-      if ((added_hash[uid] == 1) || (member_hash[uid] == 1)) {
+    function adduser(dn, cn) {
+      dn_to_cn_hash[dn] = cn;
+
+      if ((added_hash[dn] == 1) || (member_hash[dn] == 1)) {
         return null;
       }
-      added_hash[uid] = 1;
+      added_hash[dn] = 1;
 
       var newdiv = document.createElement('div');
       newdiv.appendChild(document.createTextNode(
-        cn.escapeHTML() + " (" + uid.escapeHTML() + ") "));
+        cn.escapeHTML() + " "));
 
       var undolink = document.createElement('a');
       undolink.setAttribute('href', '');
       undolink.setAttribute('onclick',
         'new Effect.Fade(Element.up(this), {afterFinish: removeElement});' +
-        'added_hash.remove("' + uid + '");' +
+        'added_hash.remove("' + jsStringEscape(dn) + '");' +
         'return false;');
       undolink.appendChild(document.createTextNode("undo"));
       newdiv.appendChild(undolink);
 
-      var uidInfo = document.createElement('input');
-      uidInfo.setAttribute('type', 'hidden');
-      uidInfo.setAttribute('name', 'uidadd');
-      uidInfo.setAttribute('value', uid);
-      newdiv.appendChild(uidInfo);
+      var dnInfo = document.createElement('input');
+      dnInfo.setAttribute('type', 'hidden');
+      dnInfo.setAttribute('name', 'dnadd');
+      dnInfo.setAttribute('value', dn);
+      newdiv.appendChild(dnInfo);
 
       newdiv.style.display = 'none';
       $('newmembers').appendChild(newdiv);
@@ -71,8 +80,8 @@
       return newdiv
     }
 
-    function adduserHandler(element, uid, cn) {
-      var newdiv = adduser(uid, cn)
+    function adduserHandler(element, dn, cn) {
+      var newdiv = adduser(dn, cn)
       if (newdiv != null) {
         new Effect.Fade(Element.up(element));
         new Effect.Appear(newdiv);
@@ -80,27 +89,28 @@
       }
     }
 
-    function removeuser(uid, cn) {
-      uid_to_cn_hash[uid] = cn;
+    function removeuser(dn, cn) {
+      dn_to_cn_hash[dn] = cn;
 
       var newdiv = document.createElement('div');
       newdiv.appendChild(document.createTextNode(
-        cn.escapeHTML() + " (" + uid.escapeHTML() + ") "));
-
+        cn.escapeHTML() + " "));
+
+      orig_div_id = dn_to_member_div_id[dn];
       var undolink = document.createElement('a');
       undolink.setAttribute('href', '');
       undolink.setAttribute('onclick',
         'new Effect.Fade(Element.up(this), {afterFinish: removeElement});' +
-        "new Effect.Appear($('member-" + uid + "'));" +
+        "new Effect.Appear($('" + orig_div_id + "'));" +
         'return false;');
       undolink.appendChild(document.createTextNode("undo"));
       newdiv.appendChild(undolink);
 
-      var uidInfo = document.createElement('input');
-      uidInfo.setAttribute('type', 'hidden');
-      uidInfo.setAttribute('name', 'uiddel');
-      uidInfo.setAttribute('value', uid);
-      newdiv.appendChild(uidInfo);
+      var dnInfo = document.createElement('input');
+      dnInfo.setAttribute('type', 'hidden');
+      dnInfo.setAttribute('name', 'dndel');
+      dnInfo.setAttribute('value', dn);
+      newdiv.appendChild(dnInfo);
 
       newdiv.style.display = 'none';
       $('delmembers').appendChild(newdiv);
@@ -108,8 +118,8 @@
       return newdiv
     }
 
-    function removeuserHandler(element, uid, cn) {
-      var newdiv = removeuser(uid, cn);
+    function removeuserHandler(element, dn, cn) {
+      var newdiv = removeuser(dn, cn);
       new Effect.Fade(Element.up(element));
       new Effect.Appear(newdiv);
       /* Element.up(element).remove(); */
@@ -141,8 +151,8 @@
     }
 
     function preSubmit() {
-      var json = uid_to_cn_hash.toJSON();
-      $('form_uid_to_cn_json').value = json;
+      var json = dn_to_cn_hash.toJSON();
+      $('form_dn_to_cn_json').value = json;
       return true;
     }
   </script>
@@ -207,20 +217,32 @@
       </div>
 
       <div>
-        <div py:for="member in members" id="member-${member.get('uid')}">
+        <?python div_counter = 1 ?>
+        <div py:for="member in members" id="member-${div_counter}">
           <?python
+          member_dn = member.get('dn')
+          member_dn_esc = ipahelper.javascript_string_escape(member_dn)
+
           member_uid = member.get('uid')
+          member_uid_esc = ipahelper.javascript_string_escape(member_uid)
+
           member_name = "%s %s" % (member.get('givenname', ''),
                                    member.get('sn', ''))
+          member_name_esc = ipahelper.javascript_string_escape(member_name)
           ?>
           ${member_name} (${member_uid})
           <a href="#" 
-            onclick="removeuserHandler(this, '${member_uid}', '${member_name}');
+            onclick="removeuserHandler(this, '${member_dn_esc}',
+                                       '${member_name_esc} (${member_uid_esc})');
                      return false;"
           >remove</a>
           <script type="text/javascript">
-            member_hash["${member_uid}"] = 1;
+            dn_to_member_div_id['${member_dn_esc}'] = "member-${div_counter}";
+            member_hash["${member_dn_esc}"] = 1;
           </script>
+          <?python
+          div_counter = div_counter + 1
+          ?>
         </div>
       </div>
 
@@ -272,8 +294,8 @@
      * This section restores the contents of the add and remove lists
      * dynamically if we have to refresh the page
      */
-    if ($('form_uid_to_cn_json').value != "") {
-      uid_to_cn_hash = new Hash($('form_uid_to_cn_json').value.evalJSON());
+    if ($('form_dn_to_cn_json').value != "") {
+      dn_to_cn_hash = new Hash($('form_dn_to_cn_json').value.evalJSON());
     }
 
     if ($('form_editprotected').value != "") {
@@ -283,30 +305,37 @@
   </script>
 
   <?python
-  uidadds = value.get('uidadd', [])
-  if not(isinstance(uidadds,list) or isinstance(uidadds,tuple)):
-      uidadds = [uidadds]
-
-  uiddels = value.get('uiddel', [])
-  if not(isinstance(uiddels,list) or isinstance(uiddels,tuple)):
-      uiddels = [uiddels]
+  dnadds = value.get('dnadd', [])
+  if not(isinstance(dnadds,list) or isinstance(dnadds,tuple)):
+      dnadds = [dnadds]
+
+  dndels = value.get('dndel', [])
+  if not(isinstance(dndels,list) or isinstance(dndels,tuple)):
+      dndels = [dndels]
   ?>
 
-  <script py:for="uidadd in uidadds">
-    var uid = "${uidadd}";
-    var cn = uid_to_cn_hash[uid];
-    var newdiv = adduser(uid, cn);
+  <script py:for="dnadd in dnadds">
+    <?python
+    dnadd_esc = ipahelper.javascript_string_escape(dnadd)
+    ?>
+    var dn = "${dnadd_esc}";
+    var cn = dn_to_cn_hash[dn];
+    var newdiv = adduser(dn, cn);
     if (newdiv != null) {
       newdiv.style.display = 'block';
     }
   </script>
 
-  <script py:for="uiddel in uiddels">
-    var uid = "${uiddel}";
-    var cn = uid_to_cn_hash[uid];
-    var newdiv = removeuser(uid, cn);
+  <script py:for="dndel in dndels">
+    <?python
+    dndel_esc = ipahelper.javascript_string_escape(dndel)
+    ?>
+    var dn = "${dndel_esc}";
+    var cn = dn_to_cn_hash[dn];
+    var newdiv = removeuser(dn, cn);
     newdiv.style.display = 'block';
-    $('member-' + uid).style.display = 'none';
+    orig_div_id = dn_to_member_div_id[dn]
+    $(orig_div_id).style.display = 'none';
   </script>
 
 </div>
diff -r 5bc5ed865060 -r d9bfdc313e95 ipa-server/ipa-gui/ipagui/templates/master.kid
--- a/ipa-server/ipa-gui/ipagui/templates/master.kid	Wed Sep 26 15:47:34 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/master.kid	Thu Sep 27 11:27:33 2007 -0700
@@ -11,6 +11,7 @@
     </style>
     <script type="text/javascript" charset="utf-8" src="${tg.url('/static/javascript/prototype.js')}"></script>
     <script type="text/javascript" charset="utf-8" src="${tg.url('/static/javascript/scriptaculous.js?load=effects')}"></script>
+    <script type="text/javascript" charset="utf-8" src="${tg.url('/static/javascript/ipautil.js')}"></script>
 </head>
 
 <body py:match="item.tag=='{http://www.w3.org/1999/xhtml}body'" py:attrs="item.items()">
diff -r 5bc5ed865060 -r d9bfdc313e95 ipa-server/ipa-gui/ipagui/templates/userlistajax.kid
--- a/ipa-server/ipa-gui/ipagui/templates/userlistajax.kid	Wed Sep 26 15:47:34 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/userlistajax.kid	Thu Sep 27 11:27:33 2007 -0700
@@ -1,24 +1,42 @@
 <div xmlns:py="http://purl.org/kid/ns#">
+
+<?python
+from ipagui.helpers import ipahelper
+?>
     <div id="search-results-count">
     </div>
+    <?python
+    criteria_esc = ipahelper.javascript_string_escape(uid)
+    ?>
     <script type="text/javascript">
-      search_string = "${uid}";
+      search_string = "${criteria_esc}";
       results_counter = 0;
     </script>
+    <?python search_div_counter = 1 ?>
     <div py:if='(users != None) and (len(users) > 0)'>
-        <div py:for="user in users" id="search-${user.uid}">
+        <div py:for="user in users" id="search-${search_div_counter}">
+          <?python
+          user_dn_esc = ipahelper.javascript_string_escape(user.dn)
+          user_uid_esc = ipahelper.javascript_string_escape(user.uid)
+          user_cn_esc = ipahelper.javascript_string_escape(user.cn)
+          ?>
           <script type="text/javascript">
-            if ((added_hash["${user.uid}"] == 1) ||
-                (member_hash["${user.uid}"] == 1)) {
-              $("search-${user.uid}").style.display = 'none';
+            if ((added_hash["${user_dn_esc}"] == 1) ||
+                (member_hash["${user_dn_esc}"] == 1)) {
+              $("search-${search_div_counter}").style.display = 'none';
             } else {
               results_counter = results_counter + 1;
             }
           </script>
           ${user.givenName} ${user.sn} (${user.uid})
-          <a href="" 
-            onclick="adduserHandler(this, '${user.uid}', '${user.cn}'); return false;"
+          <a href=""
+            onclick="adduserHandler(this, '${user_dn_esc}',
+                                   '${user_cn_esc} (${user_uid_esc})');
+                     return false;"
           >add</a>
+          <?python
+          search_div_counter = search_div_counter + 1
+          ?>
         </div>
     </div>
     <script type="text/javascript">
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 4054 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/freeipa-devel/attachments/20070927/ed503f62/attachment.bin>


More information about the Freeipa-devel mailing list