From 67c5adc7c867edaae8982eae0650a2622552b358 Mon Sep 17 00:00:00 2001
From: Brian Major <brian.major@nrc-cnrc.gc.ca>
Date: Fri, 17 Oct 2014 09:12:52 -0700
Subject: [PATCH] s1666 - start of work to list all group names

---
 .../nrc/cadc/ac/server/GroupPersistence.java  | 10 +++
 .../nrc/cadc/ac/server/ldap/LdapGroupDAO.java | 55 +++++++++++++
 .../ac/server/ldap/LdapGroupPersistence.java  | 27 ++++++-
 .../ac/server/web/GroupsActionFactory.java    |  7 +-
 .../ac/server/web/GroupActionFactoryTest.java |  4 +-
 .../src/ca/nrc/cadc/ac/client/GMSClient.java  | 79 +++++++++++++++++++
 6 files changed, 177 insertions(+), 5 deletions(-)

diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java
index caf9dc42..7637d728 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java
@@ -81,6 +81,16 @@ import ca.nrc.cadc.net.TransientException;
 
 public abstract interface GroupPersistence<T extends Principal>
 {
+    /**
+     * Get all group names.
+     * 
+     * @return A collection of strings.
+     * @throws TransientException If an temporary, unexpected problem occurred.
+     * @throws AccessControlException If the operation is not permitted.
+     */
+    public Collection<String> getGroupNames()
+            throws TransientException, AccessControlException;
+    
     /**
      * Get the group with the given Group ID.
      *
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java
index b85a4a31..93d29652 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java
@@ -305,6 +305,61 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
             throw new RuntimeException("Unexpected LDAP exception", e);
         }
     }
+    
+    
+    /**
+     * Get all group names.
+     * 
+     * @return A collection of strings
+     * 
+     * @throws TransientException If an temporary, unexpected problem occurred.
+     */
+    public Collection<String> getGroupNames() throws TransientException,
+               AccessControlException
+    {
+        try
+        {
+            Filter filter = null;
+            String [] attributes = new String[] {"cn", "nsaccountlock"};
+            
+            SearchRequest searchRequest = 
+                    new SearchRequest(config.getGroupsDN(), 
+                                      SearchScope.SUB, filter, attributes);
+    
+            searchRequest.addControl(
+                    new ProxiedAuthorizationV2RequestControl("dn:" + 
+                            getSubjectDN().toNormalizedString()));
+    
+            SearchResult searchResult = null;
+            try
+            {
+                searchResult = getConnection().search(searchRequest);
+            }
+            catch (LDAPSearchException e)
+            {
+                if (e.getResultCode() == ResultCode.NO_SUCH_OBJECT)
+                {
+                    logger.debug("Count not find groups root", e);
+                    throw new IllegalStateException("Count not find groups root");
+                }
+            }
+            
+            LdapDAO.checkLdapResult(searchResult.getResultCode());
+            List<String> groupNames = new ArrayList<String>();
+            for (SearchResultEntry next : searchResult.getSearchEntries())
+            {
+                groupNames.add(next.getAttributeValue("cn"));
+            }
+            
+            return groupNames;
+        }
+        catch (LDAPException e1)
+        {
+            LdapDAO.checkLdapResult(e1.getResultCode());
+            throw new IllegalStateException("Unexpected exception: " + e1.getMatchedDN(), e1);
+        }
+        
+    }
 
     /**
      * Get the group with the given Group ID.
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java
index 4ef7ef53..9fc50999 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java
@@ -93,7 +93,32 @@ public class LdapGroupPersistence<T extends Principal>
     {
         config = LdapConfig.getLdapConfig();
     }
-
+    
+    public Collection<String> getGroupNames() throws TransientException,
+        AccessControlException
+    {
+        LdapGroupDAO<T> groupDAO = null;
+        LdapUserDAO<T> userDAO = null;
+        try
+        {
+            userDAO = new LdapUserDAO<T>(config);
+            groupDAO = new LdapGroupDAO<T>(config, userDAO);
+            Collection<String> ret = groupDAO.getGroupNames();
+            return ret;
+        }
+        finally
+        {
+            if (groupDAO != null)
+            {
+                groupDAO.close();
+            }
+            if (userDAO != null)
+            {
+                userDAO.close();
+            }
+        }
+    }
+    
     public Group getGroup(String groupName)
         throws GroupNotFoundException, TransientException,
                AccessControlException
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsActionFactory.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsActionFactory.java
index f71e21c2..d776f56c 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsActionFactory.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsActionFactory.java
@@ -68,12 +68,15 @@
  */
 package ca.nrc.cadc.ac.server.web;
 
-import ca.nrc.cadc.util.StringUtil;
 import java.io.IOException;
 import java.net.URLDecoder;
+
 import javax.servlet.http.HttpServletRequest;
+
 import org.apache.log4j.Logger;
 
+import ca.nrc.cadc.util.StringUtil;
+
 public class GroupsActionFactory
 {
     private static final Logger log = Logger.getLogger(GroupsActionFactory.class);
@@ -109,7 +112,7 @@ public class GroupsActionFactory
         {
             if (method.equals("GET"))
             {
-                action = new ListGroupsAction(logInfo);
+                action = new GetGroupNamesAction(logInfo);
             }
             else if (method.equals("PUT"))
             {
diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GroupActionFactoryTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GroupActionFactoryTest.java
index 22df7faa..849d4d71 100644
--- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GroupActionFactoryTest.java
+++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GroupActionFactoryTest.java
@@ -189,7 +189,7 @@ public class GroupActionFactoryTest
     }
 
     @Test
-    public void testCreateListGroupsAction()
+    public void testCreateGetGroupNamesAction()
     {
         try
         {
@@ -199,7 +199,7 @@ public class GroupActionFactoryTest
             EasyMock.replay(request);
             GroupsAction action = GroupsActionFactory.getGroupsAction(request, null);
             EasyMock.verify(request);
-            Assert.assertTrue("Wrong action", action instanceof ListGroupsAction);
+            Assert.assertTrue("Wrong action", action instanceof GetGroupNamesAction);
         }
         catch (Throwable t)
         {
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java
index 6f1489c9..f66b961e 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java
@@ -68,9 +68,12 @@
  */
 package ca.nrc.cadc.ac.client;
 
+import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -79,6 +82,7 @@ import java.security.AccessControlContext;
 import java.security.AccessControlException;
 import java.security.AccessController;
 import java.security.Principal;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -106,6 +110,8 @@ import ca.nrc.cadc.net.HttpPost;
 import ca.nrc.cadc.net.HttpUpload;
 import ca.nrc.cadc.net.NetUtil;
 
+import com.csvreader.CsvReader;
+
 /**
  * Client class for performing group searching and group actions
  * with the access control web service.
@@ -293,6 +299,78 @@ public class GMSClient
             throw new RuntimeException(bug);
         }
     }
+    
+    /**
+     * Get the all group names.
+     *
+     * @return The list of names.
+     * @throws AccessControlException If unauthorized to perform this operation.
+     * @throws java.io.IOException
+     */
+    public List<String> getGroupNames()
+        throws AccessControlException, IOException
+    {
+        URL getGroupNamesURL = new URL(this.baseURL + "/groups");
+        log.debug("getGroupNames request to " + getGroupNamesURL.toString());
+        
+        HttpURLConnection conn = 
+                (HttpURLConnection) getGroupNamesURL.openConnection();
+        conn.setRequestMethod("GET");
+
+        SSLSocketFactory sf = getSSLSocketFactory();
+        if ((sf != null) && ((conn instanceof HttpsURLConnection)))
+        {
+            ((HttpsURLConnection) conn)
+                    .setSSLSocketFactory(sf);
+        }
+        int responseCode = -1;
+        try
+        {
+            responseCode = conn.getResponseCode();
+        }
+        catch(Exception e)
+        {
+            throw new AccessControlException(e.getMessage());
+        }
+        
+        if (responseCode != 200)
+        {
+            String errMessage = NetUtil.getErrorBody(conn);
+            log.debug("deleteGroup response " + responseCode + ": " + 
+                      errMessage);
+
+            if ((responseCode == 401) || (responseCode == 403) || 
+                    (responseCode == -1))
+            {
+                throw new AccessControlException(errMessage);
+            }
+            if (responseCode == 400)
+            {
+                throw new IllegalArgumentException(errMessage);
+            }
+            throw new IOException("HttpResponse (" + responseCode + ") - " + errMessage);
+        }
+
+        try
+        {
+            List<String> groupNames = new ArrayList<String>();
+            Reader ioReader = new InputStreamReader(conn.getInputStream());
+            BufferedReader br = new BufferedReader(ioReader);
+            CsvReader reader = new CsvReader(br);
+            
+            for (int i=0; i<reader.getColumnCount(); i++)
+            {
+                groupNames.add(reader.get(i));
+            }
+            
+            return groupNames;
+        }
+        catch (Exception bug)
+        {
+            log.error("Unexpected exception", bug);
+            throw new RuntimeException(bug);
+        }
+    }
 
     /**
      * Update a group.
@@ -948,6 +1026,7 @@ public class GMSClient
     public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory)
     {
         this.sslSocketFactory = sslSocketFactory;
+        clearCache();
     }
     
     /**
-- 
GitLab