From 685d663682c4034d5af9776ef90a99daabb9c38d Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Wed, 12 Nov 2014 11:58:20 -0500
Subject: [PATCH] Ticket 47946 - ACI's are replaced by "ACI_ALL" after editing
 goup of ACI's including invalid one

Bug Description:  When the console processes an aci update, it removes all the aci's and reads
                  the "updated" aci's.  It does something similiar when checking hte syntax, where
                  it removes the aci's and then adds a generic "allow(all)" aci, and the current
                  aci that we want to check the syntax.  If the syntax is invalid, we do not restore
                  the aci's.

Fix Description:  I reworked how we update aci's, where we only "replace" aci's that were modified,
                  instead of removing all aci's and adding them all back.  In order to properly check
                  if an aci has the correct syntax it must be added (somewhere).  Added a new testACI()
                  method that will test if an aci passes the syntax check by adding the aci to the
                  ACL plugin entry, and then removing it right away.  Using this approach we do not
                  automatically delete invalid aci's that were already present in the db, and we do
                  not delete valid aci's that were attempted to be modified into invalid aci's.

https://fedorahosted.org/389/ticket/47946

Reviewed by: ?
---
 .../netscape/management/client/ace/ACIEditor.java  | 69 +++++-------------
 .../netscape/management/client/ace/ACIManager.java | 85 ++++++++++++++++------
 2 files changed, 79 insertions(+), 75 deletions(-)

diff --git a/src/com/netscape/management/client/ace/ACIEditor.java b/src/com/netscape/management/client/ace/ACIEditor.java
index 3a52a20..6fae13e 100644
--- a/src/com/netscape/management/client/ace/ACIEditor.java
+++ b/src/com/netscape/management/client/ace/ACIEditor.java
@@ -22,9 +22,12 @@ package com.netscape.management.client.ace;
 import java.awt.*;
 import java.awt.event.*;
 import java.util.*;
+
 import javax.swing.*;
 import javax.swing.event.*;
+
 import netscape.ldap.*;
+
 import com.netscape.management.client.console.*;
 import com.netscape.management.client.components.*;
 import com.netscape.management.client.util.*;
@@ -91,7 +94,8 @@ class ACIEditor extends GenericDialog
     private JButton modeButton = null;
     private JTextArea textArea = null;
     private boolean isInitialized = false;
-    
+    private LDAPAttribute origACIAttr = null;
+
     private static String i18n(String id)
     {
         return i18n.getString("ed", id);
@@ -585,68 +589,29 @@ class ACIEditor extends GenericDialog
     class SyntaxActionListener implements ActionListener
     {
         final String ACI_ALL = "(targetattr=\"*\")(version 3.0; acl \"Allow Everyone\"; allow (all) (userdn = \"ldap:///anyone\") ;)";
+        final String ACL_PLUGIN_DN = "cn=ACL Plugin,cn=plugins,cn=config";
+
         public void actionPerformed(ActionEvent event)
         {
             LDAPAttribute oldACIAttr = null;
             LDAPAttribute testACIAttr = null;
             LDAPModification mod = null;
-            boolean isSyntaxOK = false;
-            try
-            {
-                LDAPEntry entry = aciLdc.read(aciDN, new String[] {"aci"});
-                if (entry != null) 
-                    oldACIAttr = entry.getAttribute("aci");
-                testACIAttr = new LDAPAttribute("aci");
-                testACIAttr.addValue(ACI_ALL);
-                testACIAttr.addValue(getACI());
-                mod = new LDAPModification(LDAPModification.REPLACE, testACIAttr);
-                try
-                {
-                    aciLdc.modify(aciDN, mod);
-                    isSyntaxOK = true;
-                }
-                catch (LDAPException e)
-                {
-                    isSyntaxOK = false;
-                    Debug.println("ACI Write Error: " + e.getLDAPResultCode());
-                    Debug.println("Message: " + e.getLDAPErrorMessage());
-                }
-                try
-                {
-                    if(oldACIAttr != null)
-                        mod = new LDAPModification(LDAPModification.REPLACE, oldACIAttr);
-                    else
-                        mod = new LDAPModification(LDAPModification.DELETE, testACIAttr);
-                    aciLdc.modify(aciDN, mod);
-                }
-                catch (LDAPException e)
-                {
-                    Debug.println("ACI Replace Error: " + e.getLDAPResultCode());
-                }
-                
-                Container parent = SwingUtilities.getAncestorOfClass(JDialog.class, contentPanel);
-                
-                if(isSyntaxOK)
-                {
-                    String title = i18n("syntaxPassedTitle");
-                    String msg = i18n("syntaxPassedMsg");
-                    JOptionPane.showMessageDialog(parent, msg, title, JOptionPane.INFORMATION_MESSAGE);
-                }
-                else
-                {
-                    String title = i18n("syntaxFailedTitle");
-                    String msg = i18n("syntaxFailedMsg");
-                    JOptionPane.showMessageDialog(parent, msg, title, JOptionPane.ERROR_MESSAGE);
-                }
+            Container parent = SwingUtilities.getAncestorOfClass(JDialog.class, contentPanel);
+
+            try {
+                ACIManager.testACI(aciLdc, getACI());
+                String title = i18n("syntaxPassedTitle");
+                String msg = i18n("syntaxPassedMsg");
+                JOptionPane.showMessageDialog(parent, msg, title, JOptionPane.INFORMATION_MESSAGE);
             }
             catch (LDAPException e)
             {
-                Debug.println("ACI Read Error: " + e.getLDAPResultCode());
+                String title = i18n("syntaxFailedTitle");
+                String msg = i18n("syntaxFailedMsg");
+                JOptionPane.showMessageDialog(parent, msg, title, JOptionPane.ERROR_MESSAGE);
             }
-            
         }
     }
-    
 
     class ManualActionListener implements ActionListener
     {
diff --git a/src/com/netscape/management/client/ace/ACIManager.java b/src/com/netscape/management/client/ace/ACIManager.java
index 3c08bc9..4e51912 100644
--- a/src/com/netscape/management/client/ace/ACIManager.java
+++ b/src/com/netscape/management/client/ace/ACIManager.java
@@ -62,6 +62,7 @@ public class ACIManager extends GenericDialog
     private LDAPConnection aciLdc;
     private LDAPConnection ugLdc;
     private Vector extraACITabs = new Vector();
+    private static final String ACL_PLUGIN_DN = "cn=ACL Plugin,cn=plugins,cn=config";
     
     private static String i18n(String id) 
     {
@@ -220,6 +221,30 @@ public class ACIManager extends GenericDialog
             aciVector.addElement(aci);
         }
     }
+
+    public static void testACI( LDAPConnection ldc, String aci) throws LDAPException
+    {
+        // Add the aci to the ACL plugin entry to verify if its syntax is correct.
+        LDAPAttribute testACIAttr = new LDAPAttribute("aci");
+        testACIAttr = new LDAPAttribute("aci");
+        testACIAttr.addValue(aci);
+        LDAPModification mod = null;
+
+        try {
+            mod = new LDAPModification(LDAPModification.ADD, testACIAttr);
+            ldc.modify(ACL_PLUGIN_DN, mod);
+
+            mod = new LDAPModification(LDAPModification.DELETE, testACIAttr);
+            ldc.modify(ACL_PLUGIN_DN, mod);
+        }
+        catch (LDAPException e)
+        {
+            Debug.println("Failed to add/delete aci to testing entry: mod "
+                + mod.toString() + " - Error: " + e.getLDAPResultCode());
+            Debug.println("Message: " + e.getLDAPErrorMessage());
+            throw e;
+        }
+    }
     
     private JPanel createButtonPanel()
     {
@@ -393,16 +418,6 @@ public class ACIManager extends GenericDialog
         try
         {
             writeACIsFromDN(aciDN, aciVector.elements());
-            int length = aciDN.length();
-            for(int i = 0; i < length; i++)
-            {
-                String dn;
-                if(aciDN.charAt(i) == ',')
-                {
-                    dn = aciDN.substring(i+1);
-                    writeACIsFromDN(dn, aciVector.elements());
-                }
-            }
             super.okInvoked();
         }
         catch(LDAPException e)
@@ -452,35 +467,52 @@ public class ACIManager extends GenericDialog
         ACI aci = null;
         try 
         {
-            boolean isDirty = false;
             LDAPAttribute attr = new LDAPAttribute("aci");
             while(aciVector.hasMoreElements())
             {
                 aci = (ACI)aciVector.nextElement();
                 if(aci.getDN().equals(dn))
                 {
-                    if(aci.isModified())
-                       isDirty = true;
-                    
-                    if(!aci.isDeleted())
+                    if(aci.isDeleted() )
                     {
-                        String aciData = aci.getData();
+                        // Delete the original aci
+                        String aciData = aci.getOrigData();
                         attr.addValue(aciData);
+                        LDAPModification mod = new LDAPModification(LDAPModification.DELETE, attr);
+                        aciLdc.modify(dn, mod);
+                    }
+                    else if(aci.isModified())
+                    {
+                        String origData = aci.getOrigData();
+                        String currData = aci.getData();
+
+                        // First check that entry has actually changed
+                        if(!origData.equals(currData)){
+                            // Before we delete the old aci, make sure we can add the new aci.
+                            testACI(aciLdc, currData);
+
+                            // Delete the original aci first
+                            String aciData = aci.getOrigData();
+                            attr.addValue(aciData);
+                            LDAPModification mod = new LDAPModification(LDAPModification.DELETE, attr);
+                            aciLdc.modify(dn, mod);
+
+                            // Add the new/modified aci
+                            attr.removeValue(aciData);
+                            aciData = aci.getData();
+                            attr.addValue(aciData);
+                            mod = new LDAPModification(LDAPModification.ADD, attr);
+                            aciLdc.modify(dn, mod);
+                        }
                     }
                 }
             }
-            if(isDirty)
-            {
-                LDAPModification mod = new LDAPModification(LDAPModification.REPLACE, attr);
-                aciLdc.modify(dn, mod);
-            }
         }
         catch (LDAPException e)
         {
             Debug.println("ACI Write Error: " + e.getLDAPResultCode());
             Debug.println("Message: " + e.getLDAPErrorMessage());
             throw e;
-
         }
     }
     
@@ -488,6 +520,7 @@ public class ACIManager extends GenericDialog
     {
         String dn;
         String data;
+        String orig_data;
         String name;
         boolean isInherited = false;
         boolean isModified = false;
@@ -498,6 +531,7 @@ public class ACIManager extends GenericDialog
             this.dn = dn;
             this.isInherited = isInherited;
             setData(data);
+            this.orig_data = new String(data);
             setModified(isModified);
         }
         
@@ -518,10 +552,15 @@ public class ACIManager extends GenericDialog
             return data;
         }
         
+        public String getOrigData()
+        {
+            return orig_data;
+        }
+
         public void setData(String data)
         {
             this.data = data;
-            String aciName = null;
+
             ACIAttribute a = ACIAttribute.getAttribute("acl", ACIAttribute.toArray(ACIParser.getACIAttributes(data)));
             
             //bug 516529 : need to accept either acl or aci for the name
-- 
1.9.3

