diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java
index b2730be04082c9d4c9fb0bc56516e53ee677c748..380961d8e65420b6822e7f689e6d39829bd6bcdd 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java
@@ -73,10 +73,7 @@ import java.security.Principal;
 import java.util.Collection;
 import java.util.Map;
 
-import ca.nrc.cadc.ac.User;
-import ca.nrc.cadc.ac.UserAlreadyExistsException;
-import ca.nrc.cadc.ac.UserNotFoundException;
-import ca.nrc.cadc.ac.UserRequest;
+import ca.nrc.cadc.ac.*;
 import ca.nrc.cadc.net.TransientException;
 
 import com.unboundid.ldap.sdk.DN;
@@ -91,7 +88,7 @@ public interface UserPersistence<T extends Principal>
      * @throws TransientException If an temporary, unexpected problem occurred.
      * @throws AccessControlException If the operation is not permitted.
      */
-    Map<String, String> getUsers()
+    Map<String, PersonalDetails> getUsers()
             throws TransientException, AccessControlException;
     
     /**
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java
index 6d272ca3bd2f341a450b90e8c3027a6acc5ce5e0..b133948eb0ef553f34d805512682f339d7b4cce4 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java
@@ -488,15 +488,16 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
      * @return A map of string keys to string values.
      * @throws TransientException If an temporary, unexpected problem occurred.
      */
-    public Map<String, String> getUsers()
+    public Map<String, PersonalDetails> getUsers()
             throws TransientException
     {
-        final Map<String, String> users = new HashMap<String, String>();
+        final Map<String, PersonalDetails> users =
+                new HashMap<String, PersonalDetails>();
 
         try
         {
-            final Filter filter = Filter.createPresenceFilter(LDAP_COMMON_NAME);
-            final String[] attributes = new String[]{LDAP_COMMON_NAME,
+            final Filter filter = Filter.createPresenceFilter(LDAP_UID);
+            final String[] attributes = new String[]{LDAP_UID,
                                                      LDAP_FIRST_NAME,
                                                      LDAP_LAST_NAME,
                                                      LDAP_NSACCOUNTLOCK};
@@ -514,10 +515,16 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
                 {
                     if (!next.hasAttribute(LDAP_NSACCOUNTLOCK))
                     {
-                        users.put(next.getAttributeValue(LDAP_COMMON_NAME),
-                                  next.getAttributeValue(LDAP_FIRST_NAME)
-                                  + " "
-                                  + next.getAttributeValue(LDAP_LAST_NAME));
+                        final String trimmedFirstName =
+                                next.getAttributeValue(LDAP_FIRST_NAME).trim();
+                        final String trimmedLastName =
+                                next.getAttributeValue(LDAP_LAST_NAME).trim();
+                        final String trimmedUID =
+                                next.getAttributeValue(LDAP_UID).trim();
+
+                        users.put(trimmedUID,
+                                  new PersonalDetails(trimmedFirstName,
+                                                      trimmedLastName));
                     }
                 }
             }
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java
index 452598a10ea4271fba4fdd547cce682606ae80de..af7662460e342b8ae107af471b1b57bf0aa8d019 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java
@@ -68,10 +68,7 @@
  */
 package ca.nrc.cadc.ac.server.ldap;
 
-import ca.nrc.cadc.ac.User;
-import ca.nrc.cadc.ac.UserAlreadyExistsException;
-import ca.nrc.cadc.ac.UserNotFoundException;
-import ca.nrc.cadc.ac.UserRequest;
+import ca.nrc.cadc.ac.*;
 import ca.nrc.cadc.ac.server.UserPersistence;
 import ca.nrc.cadc.net.TransientException;
 import com.unboundid.ldap.sdk.DN;
@@ -100,7 +97,7 @@ public class LdapUserPersistence<T extends Principal>
         }
     }
     
-    public Map<String, String> getUsers()
+    public Map<String, PersonalDetails> getUsers()
         throws TransientException, AccessControlException
     {
         LdapUserDAO<T> userDAO = null;
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersAction.java
index 60f75a3ec9c9d070814702c3686250d8c2998c27..ce700e167925a31028583447fb0936f5b264962f 100644
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersAction.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersAction.java
@@ -80,6 +80,7 @@ import java.util.Map;
 import javax.security.auth.Subject;
 import javax.servlet.http.HttpServletResponse;
 
+import ca.nrc.cadc.ac.PersonalDetails;
 import ca.nrc.cadc.ac.User;
 import ca.nrc.cadc.ac.UserRequest;
 import org.apache.log4j.Logger;
@@ -278,7 +279,7 @@ public abstract class UsersAction
      *
      * @param users         The Map of user IDs to names.
      */
-    protected final void writeUsers(final Map<String, String> users)
+    protected final void writeUsers(final Map<String, PersonalDetails> users)
             throws IOException
     {
         response.setContentType(acceptedContentType);
diff --git a/projects/cadcAccessControl-Server/test/LdapConfig.test.properties b/projects/cadcAccessControl-Server/test/LdapConfig.test.properties
index bb88d99c07772fa45762f109b6c5c32be22651f0..0612a33b3987c7efbc6f19c01fb1b4d72efec14a 100644
--- a/projects/cadcAccessControl-Server/test/LdapConfig.test.properties
+++ b/projects/cadcAccessControl-Server/test/LdapConfig.test.properties
@@ -1,6 +1,11 @@
 # This are the configuration fields required by the Ldap ldap-dao unit tests
+# Tests are more accurate running on Port 636.  If it fails due to SSL/Security
+# issues, then make very sure the ca.crt (gimli2.cadc.dao.nrc.ca:~miscsw/ca.crt)
+# is installed in your Java Keystore:
+# scp gimli2.cadc.dao.nrc.ca:~miscsw/ca.crt /tmp/ca.crt
+# ${JAVA_HOME}/bin/keytool -importcert -keystore ${JAVA_HOME}/jre/lib/security/cacerts -file /tmp/ca.crt
 server = proc5-03.cadc.dao.nrc.ca
-port = 389
+port = 636
 proxyUser = testproxy
 usersDn = ou=Users,ou=ds,dc=testcanfar
 userRequestsDN = ou=UserRequests,ou=ds,dc=testcanfar
diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java
index fda75b28b116d178a44c4af5bff0f14e15c0cc22..fb0f533262766806509a6e4eab41606d4213945d 100644
--- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java
+++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java
@@ -102,10 +102,10 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
     static String testUserDN;
     static User<X500Principal> testUser;
     static LdapConfig config;
-    
+
     @BeforeClass
     public static void setUpBeforeClass()
-        throws Exception
+            throws Exception
     {
         Log4jInit.setLevel("ca.nrc.cadc.ac", Level.DEBUG);
 
@@ -123,12 +123,12 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
     {
         return new LdapUserDAO(config);
     }
-    
+
     String getUserID()
     {
         return "CadcDaoTestUser-" + System.currentTimeMillis();
     }
-    
+
     /**
      * Test of addUser method, of class LdapUserDAO.
      */
@@ -148,7 +148,7 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
         User<HttpPrincipal> actual = getUserDAO().addUser(userRequest);
         check(expected, actual);
     }
-    
+
     /**
      * Test of getUser method, of class LdapUserDAO.
      */
@@ -167,6 +167,8 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
                 try
                 {
                     User<X500Principal> actual = getUserDAO().getUser(testUser.getUserID());
+                    User<X500Principal> actual = getUserDAO()
+                            .getUser(testUser.getUserID());
                     check(testUser, actual);
 
                     return null;
@@ -195,19 +197,31 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
             public Object run() throws Exception
             {
                 try
-                {            
+                {
                     Collection<DN> groups = getUserDAO().getUserGroups(testUser.getUserID(), false);
                     assertNotNull(groups);
                     assertTrue(!groups.isEmpty());
+                    Collection<DN> groups =
+                            getUserDAO().getUserGroups(testUser.getUserID(),
+                                                       false);
+                    assertNotNull("Groups should not be null.", groups);
+
                     for (DN groupDN : groups)
+                    {
                         log.debug(groupDN);
-                    
+                    }
+
                     groups = getUserDAO().getUserGroups(testUser.getUserID(), true);
                     assertNotNull(groups);
                     assertTrue(!groups.isEmpty());
+                    groups = getUserDAO().getUserGroups(testUser.getUserID(),
+                                                        true);
+                    assertNotNull("Groups should not be null.", groups);
                     for (DN groupDN : groups)
+                    {
                         log.debug(groupDN);
-                    
+                    }
+
                     return null;
                 }
                 catch (Exception e)
@@ -217,7 +231,7 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
             }
         });
     }
-    
+
     /**
      * Test of getUserGroups method, of class LdapUserDAO.
      */
@@ -233,14 +247,22 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
             public Object run() throws Exception
             {
                 try
-                {   
+                {
                     boolean isMember = getUserDAO().isMember(testUser.getUserID(), "foo");
                     assertFalse(isMember);
-                    
+                    boolean isMember =
+                            getUserDAO().isMember(testUser.getUserID(), "foo");
+                    assertFalse("Membership should not exist.", isMember);
+
                     String groupDN = "cn=cadcdaotestgroup1," + config.getGroupsDN();
                     isMember = getUserDAO().isMember(testUser.getUserID(), groupDN);
                     assertTrue(isMember);
-                    
+                    String groupDN = "cn=cadcdaotestgroup1,"
+                                     + config.getGroupsDN();
+                    isMember = getUserDAO().isMember(testUser.getUserID(),
+                                                     groupDN);
+                    assertTrue("Membership should exist.", isMember);
+
                     return null;
                 }
                 catch (Exception e)
@@ -250,7 +272,7 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
             }
         });
     }
-    
+
     /**
      * Test of getMember.
      */
@@ -266,8 +288,10 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
             public Object run() throws Exception
             {
                 try
-                {   
+                {
                     User<X500Principal> actual = getUserDAO().getMember(new DN(testUserDN));
+                    User<X500Principal> actual = getUserDAO()
+                            .getMember(new DN(testUserDN));
                     check(testUser, actual);
                     return null;
                 }
@@ -277,7 +301,7 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
                 }
             }
         });
-        
+
         // should also work as a different user
         subject = new Subject();
         subject.getPrincipals().add(new HttpPrincipal("CadcDaoTest2"));
@@ -290,7 +314,12 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
             {
                 try
                 {
+<<<<<<< HEAD
                     User<X500Principal> actual = getUserDAO().getMember(new DN(testUserDN));
+=======
+                    User<X500Principal> actual = getUserDAO()
+                            .getMember(new DN(testUserDN));
+>>>>>>> 57bf534cb0ace85be32da449ca35a73e96a379b2
                     check(testUser, actual);
                     return null;
                 }
@@ -301,7 +330,7 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
             }
         });
     }
-    
+
     /**
      * Test of testGetCadcUserIDs.
      */
@@ -309,36 +338,40 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
     public void testGetCadcUserIDs() throws Exception
     {
         Subject subject = new Subject();
-       
-        
+
+
         // anonymous access
         int users1 = (Integer)Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
-        {
-            public Object run() throws Exception
-            {
-                try
-                {            
-                    
-                    int count = getUserDAO().getCadcIDs().size();
-                    assertTrue(count > 0);
-                    return count;
-                }
-                catch (Exception e)
+        int users1 = (Integer) Subject
+                .doAs(subject, new PrivilegedExceptionAction<Object>()
                 {
-                    throw new Exception("Problems", e);
-                }
-            }
-        });
-        
+                    public Object run() throws Exception
+                    {
+                        try
+                        {
+
+                            int count = getUserDAO().getCadcIDs().size();
+                            assertTrue(count > 0);
+                            return count;
+                        }
+                        catch (Exception e)
+                        {
+                            throw new Exception("Problems", e);
+                        }
+                    }
+                });
+
         // authenticated access
         subject.getPrincipals().add(testUser.getUserID());
         int users2 = (Integer)Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
+        int users2 = (Integer) Subject
+                .doAs(subject, new PrivilegedExceptionAction<Object>()
                 {
                     public Object run() throws Exception
                     {
                         try
-                        {            
-                            
+                        {
+
                             int count = getUserDAO().getCadcIDs().size();
                             assertTrue(count > 0);
                             return count;
@@ -350,6 +383,7 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
                     }
                 });
         assertEquals("User listing should be independent of the access type",
+<<<<<<< HEAD
             users1, users2);
     }
 
@@ -562,26 +596,29 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
         });
         assertNotNull(updatedUser);
         check(testUser2, updatedUser);
+=======
+                     users1, users2);
+>>>>>>> 57bf534cb0ace85be32da449ca35a73e96a379b2
     }
-    
+
     private static void check(final User<? extends Principal> user1, final User<? extends Principal> user2)
     {
         assertEquals(user1, user2);
         assertEquals(user1.details, user2.details);
         assertEquals(user1.details.size(), user2.details.size());
         assertEquals(user1.getIdentities(), user2.getIdentities());
-        for(UserDetails d1 : user1.details)
+        for (UserDetails d1 : user1.details)
         {
             assertTrue(user2.details.contains(d1));
-            if(d1 instanceof PersonalDetails)
+            if (d1 instanceof PersonalDetails)
             {
-                PersonalDetails pd1 = (PersonalDetails)d1;
+                PersonalDetails pd1 = (PersonalDetails) d1;
                 boolean found = false;
-                for(UserDetails d2 : user2.details)
+                for (UserDetails d2 : user2.details)
                 {
-                    if(d2 instanceof PersonalDetails)
+                    if (d2 instanceof PersonalDetails)
                     {
-                        PersonalDetails pd2 = (PersonalDetails)d2;
+                        PersonalDetails pd2 = (PersonalDetails) d2;
                         assertEquals(pd1, pd2); // already done in contains above but just in case
                         assertEquals(pd1.address, pd2.address);
                         assertEquals(pd1.city, pd2.city);
@@ -612,7 +649,7 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest
                 }
             }
         }
-        
+
     }
-    
+
 }
diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUsersActionTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUsersActionTest.java
index e8f7004fda1c3462fdf4b82e616b2227df24bc00..f1dc7a29aeb521d739a16325c62b97af3a83510a 100644
--- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUsersActionTest.java
+++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUsersActionTest.java
@@ -69,6 +69,7 @@
 package ca.nrc.cadc.ac.server.web.users;
 
 
+import ca.nrc.cadc.ac.PersonalDetails;
 import ca.nrc.cadc.ac.server.UserPersistence;
 import ca.nrc.cadc.auth.HttpPrincipal;
 import org.apache.log4j.Level;
@@ -112,11 +113,13 @@ public class GetUsersActionTest
                 createMock(HttpServletResponse.class);
         final UserPersistence<HttpPrincipal> mockUserPersistence =
                 createMock(UserPersistence.class);
-        final Map<String, String> userEntries = new HashMap<String, String>();
+        final Map<String, PersonalDetails> userEntries =
+                new HashMap<String, PersonalDetails>();
 
         for (int i = 1; i <= 5; i++)
         {
-            userEntries.put("USER_" + i, "USER " + i);
+            userEntries.put("USER_" + i,
+                            new PersonalDetails("USER", Integer.toString(i)));
         }
 
         final GetUsersAction testSubject = new GetUsersAction(null)
@@ -143,7 +146,7 @@ public class GetUsersActionTest
         testSubject.doAction(null, mockResponse);
 
         final JSONArray expected =
-                new JSONArray("[{\"id\":\"USER_1\",\"name\":\"USER 1\"},{\"id\":\"USER_3\",\"name\":\"USER 3\"},{\"id\":\"USER_2\",\"name\":\"USER 2\"},{\"id\":\"USER_4\",\"name\":\"USER 4\"},{\"id\":\"USER_5\",\"name\":\"USER 5\"}]");
+                new JSONArray("[{\"id\":\"USER_1\",\"firstName\":\"USER\",\"lastName\":\"1\"},{\"id\":\"USER_3\",\"firstName\":\"USER\",\"lastName\":\"3\"},{\"id\":\"USER_2\",\"firstName\":\"USER\",\"lastName\":\"2\"},{\"id\":\"USER_4\",\"firstName\":\"USER\",\"lastName\":\"4\"},{\"id\":\"USER_5\",\"firstName\":\"USER\",\"lastName\":\"5\"}]");
         final JSONArray result = new JSONArray(writer.toString());
 
         JSONAssert.assertEquals(expected, result, true);
@@ -158,11 +161,13 @@ public class GetUsersActionTest
                 createMock(HttpServletResponse.class);
         final UserPersistence<HttpPrincipal> mockUserPersistence =
                 createMock(UserPersistence.class);
-        final Map<String, String> userEntries = new HashMap<String, String>();
+        final Map<String, PersonalDetails> userEntries =
+                new HashMap<String, PersonalDetails>();
 
         for (int i = 1; i <= 5; i++)
         {
-            userEntries.put("USER_" + i, "USER " + i);
+            userEntries.put("USER_" + i,
+                            new PersonalDetails("USER", Integer.toString(i)));
         }
 
         final GetUsersAction testSubject = new GetUsersAction(null)
@@ -189,19 +194,24 @@ public class GetUsersActionTest
         final String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
                                 "<users>\r\n" +
                                 "  <user id=\"USER_1\">\r\n" +
-                                "    <name>USER 1</name>\r\n" +
+                                "    <firstName>USER</firstName>\r\n" +
+                                "    <lastName>1</lastName>\r\n" +
                                 "  </user>\r\n" +
                                 "  <user id=\"USER_3\">\r\n" +
-                                "    <name>USER 3</name>\r\n" +
+                                "    <firstName>USER</firstName>\r\n" +
+                                "    <lastName>3</lastName>\r\n" +
                                 "  </user>\r\n" +
                                 "  <user id=\"USER_2\">\r\n" +
-                                "    <name>USER 2</name>\r\n" +
+                                "    <firstName>USER</firstName>\r\n" +
+                                "    <lastName>2</lastName>\r\n" +
                                 "  </user>\r\n" +
                                 "  <user id=\"USER_4\">\r\n" +
-                                "    <name>USER 4</name>\r\n" +
+                                "    <firstName>USER</firstName>\r\n" +
+                                "    <lastName>4</lastName>\r\n" +
                                 "  </user>\r\n" +
                                 "  <user id=\"USER_5\">\r\n" +
-                                "    <name>USER 5</name>\r\n" +
+                                "    <firstName>USER</firstName>\r\n" +
+                                "    <lastName>5</lastName>\r\n" +
                                 "  </user>\r\n" +
                                 "</users>\r\n";
         final String result = writer.toString();
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 159e48eaddffdb4f62b6fea3a1eea8af3b29fc33..8f4eab02036b1155294d80566c74a434875ad142 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java
@@ -68,12 +68,7 @@
  */
 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.InputStream;
-import java.io.InputStreamReader;
+import java.io.*;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -93,16 +88,14 @@ import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLSocketFactory;
 import javax.security.auth.Subject;
 
+import ca.nrc.cadc.ac.*;
+import ca.nrc.cadc.auth.HttpPrincipal;
+import ca.nrc.cadc.util.StringUtil;
 import org.apache.log4j.Logger;
 
-import ca.nrc.cadc.ac.Group;
-import ca.nrc.cadc.ac.GroupAlreadyExistsException;
-import ca.nrc.cadc.ac.GroupNotFoundException;
 import ca.nrc.cadc.ac.xml.GroupReader;
 import ca.nrc.cadc.ac.xml.GroupWriter;
 import ca.nrc.cadc.ac.xml.GroupsReader;
-import ca.nrc.cadc.ac.Role;
-import ca.nrc.cadc.ac.UserNotFoundException;
 import ca.nrc.cadc.auth.AuthenticationUtil;
 import ca.nrc.cadc.auth.SSLUtil;
 import ca.nrc.cadc.net.HttpDownload;
@@ -110,6 +103,7 @@ import ca.nrc.cadc.net.HttpPost;
 import ca.nrc.cadc.net.HttpUpload;
 import ca.nrc.cadc.net.InputStreamWrapper;
 import ca.nrc.cadc.net.NetUtil;
+import org.json.JSONObject;
 
 
 /**
@@ -119,21 +113,21 @@ import ca.nrc.cadc.net.NetUtil;
 public class GMSClient
 {
     private static final Logger log = Logger.getLogger(GMSClient.class);
-    
+
     // socket factory to use when connecting
     private SSLSocketFactory sslSocketFactory;
     private SSLSocketFactory mySocketFactory;
-    
+
     private String baseURL;
 
     /**
      * Constructor.
-     * 
+     *
      * @param baseURL The URL of the supporting access control web service
-     * obtained from the registry.
+     *                obtained from the registry.
      */
-    public GMSClient(String baseURL)
-        throws IllegalArgumentException
+    public GMSClient(final String baseURL)
+            throws IllegalArgumentException
     {
         if (baseURL == null)
         {
@@ -145,7 +139,7 @@ public class GMSClient
         }
         catch (MalformedURLException e)
         {
-            throw new IllegalArgumentException("URL is malformed: " + 
+            throw new IllegalArgumentException("URL is malformed: " +
                                                e.getMessage());
         }
 
@@ -169,6 +163,63 @@ public class GMSClient
         throw new UnsupportedOperationException("Not yet implemented");
     }
 
+
+
+    /**
+     * Obtain all of the users as userID - name in JSON format.
+     *
+     * @return List of HTTP Principal users.
+     * @throws IOException Any errors in reading.
+     */
+    public List<User<HttpPrincipal>> getDisplayUsers() throws IOException
+    {
+        final List<User<HttpPrincipal>> webUsers =
+                new ArrayList<User<HttpPrincipal>>();
+
+        final HttpDownload httpDownload =
+                createDisplayUsersHTTPDownload(webUsers);
+
+        httpDownload.setRequestProperty("Accept", "application/json");
+        httpDownload.run();
+
+        final Throwable error = httpDownload.getThrowable();
+
+        if (error != null)
+        {
+            final String errMessage = error.getMessage();
+            final int responseCode = httpDownload.getResponseCode();
+
+            log.debug("getDisplayUsers response " + responseCode + ": " +
+                      errMessage);
+
+            if ((responseCode == 401) || (responseCode == 403) ||
+                (responseCode == -1))
+            {
+                throw new AccessControlException(errMessage);
+            }
+            else if (responseCode == 400)
+            {
+                throw new IllegalArgumentException(errMessage);
+            }
+
+            throw new IOException("HttpResponse (" + responseCode + ") - "
+                                  + errMessage);
+        }
+
+        log.debug("Content-Length: " + httpDownload.getContentLength());
+        log.debug("Content-Type: " + httpDownload.getContentType());
+
+        return webUsers;
+    }
+
+    HttpDownload createDisplayUsersHTTPDownload(
+            final List<User<HttpPrincipal>> webUsers) throws IOException
+    {
+        final URL usersListURL = new URL(this.baseURL + "/users");
+        return new HttpDownload(usersListURL,
+                                new JSONUserListInputStreamWrapper(webUsers));
+    }
+
     /**
      * Create a new group.
      *
@@ -176,17 +227,17 @@ public class GMSClient
      * @return The newly created group will all the information.
      * @throws GroupAlreadyExistsException If a group with the same name already
      *                                     exists.
-     * @throws AccessControlException If unauthorized to perform this operation.
+     * @throws AccessControlException      If unauthorized to perform this operation.
      * @throws UserNotFoundException
      * @throws IOException
      */
     public Group createGroup(Group group)
-        throws GroupAlreadyExistsException, AccessControlException, 
-               UserNotFoundException, IOException
+            throws GroupAlreadyExistsException, AccessControlException,
+                   UserNotFoundException, IOException
     {
         URL createGroupURL = new URL(this.baseURL + "/groups");
         log.debug("createGroupURL request to " + createGroupURL.toString());
-        
+
         // reset the state of the cache
         clearCache();
 
@@ -207,8 +258,8 @@ public class GMSClient
         {
             log.debug("createGroup throwable", error);
             // transfer returns a -1 code for anonymous uploads.
-            if ((transfer.getResponseCode() == -1) || 
-                (transfer.getResponseCode() == 401) || 
+            if ((transfer.getResponseCode() == -1) ||
+                (transfer.getResponseCode() == 401) ||
                 (transfer.getResponseCode() == 403))
             {
                 throw new AccessControlException(error.getMessage());
@@ -251,7 +302,7 @@ public class GMSClient
      * @throws java.io.IOException
      */
     public Group getGroup(String groupName)
-        throws GroupNotFoundException, AccessControlException, IOException
+            throws GroupNotFoundException, AccessControlException, IOException
     {
         URL getGroupURL = new URL(this.baseURL + "/groups/" + groupName);
         log.debug("getGroup request to " + getGroupURL.toString());
@@ -264,10 +315,11 @@ public class GMSClient
         Throwable error = transfer.getThrowable();
         if (error != null)
         {
-            log.debug("getGroup throwable (" + transfer.getResponseCode() + ")", error);
+            log.debug("getGroup throwable (" + transfer
+                    .getResponseCode() + ")", error);
             // transfer returns a -1 code for anonymous access.
-            if ((transfer.getResponseCode() == -1) || 
-                (transfer.getResponseCode() == 401) || 
+            if ((transfer.getResponseCode() == -1) ||
+                (transfer.getResponseCode() == 401) ||
                 (transfer.getResponseCode() == 403))
             {
                 throw new AccessControlException(error.getMessage());
@@ -295,7 +347,7 @@ public class GMSClient
             throw new RuntimeException(bug);
         }
     }
-    
+
     /**
      * Get the all group names.
      *
@@ -304,7 +356,7 @@ public class GMSClient
      * @throws java.io.IOException
      */
     public List<String> getGroupNames()
-        throws AccessControlException, IOException
+            throws AccessControlException, IOException
     {
         final URL getGroupNamesURL = new URL(this.baseURL + "/groups");
         log.debug("getGroupNames request to " + getGroupNamesURL.toString());
@@ -312,26 +364,28 @@ public class GMSClient
         final List<String> groupNames = new ArrayList<String>();
         final HttpDownload httpDownload =
                 new HttpDownload(getGroupNamesURL, new InputStreamWrapper()
-        {
-            @Override
-            public void read(final InputStream inputStream) throws IOException
-            {
-                try
                 {
-                    InputStreamReader inReader = new InputStreamReader(inputStream);
-                    BufferedReader reader = new BufferedReader(inReader);
-                    String line;
-                    while ((line = reader.readLine()) != null) {
-                        groupNames.add(line);
+                    @Override
+                    public void read(final InputStream inputStream) throws
+                                                                    IOException
+                    {
+                        try
+                        {
+                            InputStreamReader inReader = new InputStreamReader(inputStream);
+                            BufferedReader reader = new BufferedReader(inReader);
+                            String line;
+                            while ((line = reader.readLine()) != null)
+                            {
+                                groupNames.add(line);
+                            }
+                        }
+                        catch (Exception bug)
+                        {
+                            log.error("Unexpected exception", bug);
+                            throw new RuntimeException(bug);
+                        }
                     }
-                }
-                catch (Exception bug)
-                {
-                    log.error("Unexpected exception", bug);
-                    throw new RuntimeException(bug);
-                }
-            }
-        });
+                });
 
         httpDownload.setSSLSocketFactory(getSSLSocketFactory());
         httpDownload.run();
@@ -346,8 +400,8 @@ public class GMSClient
             log.debug("getGroupNames response " + responseCode + ": " +
                       errMessage);
 
-            if ((responseCode == 401) || (responseCode == 403) || 
-                    (responseCode == -1))
+            if ((responseCode == 401) || (responseCode == 403) ||
+                (responseCode == -1))
             {
                 throw new AccessControlException(errMessage);
             }
@@ -370,36 +424,37 @@ public class GMSClient
      * @param group The update group object.
      * @return The group after update.
      * @throws IllegalArgumentException If cyclical membership is detected.
-     * @throws GroupNotFoundException If the group was not found.
-     * @throws UserNotFoundException If a member was not found.
-     * @throws AccessControlException If unauthorized to perform this operation.
+     * @throws GroupNotFoundException   If the group was not found.
+     * @throws UserNotFoundException    If a member was not found.
+     * @throws AccessControlException   If unauthorized to perform this operation.
      * @throws java.io.IOException
      */
     public Group updateGroup(Group group)
-        throws IllegalArgumentException, GroupNotFoundException, UserNotFoundException,
-               AccessControlException, IOException
+            throws IllegalArgumentException, GroupNotFoundException,
+                   UserNotFoundException,
+                   AccessControlException, IOException
     {
         URL updateGroupURL = new URL(this.baseURL + "/groups/" + group.getID());
         log.debug("updateGroup request to " + updateGroupURL.toString());
-        
+
         // reset the state of the cache
         clearCache();
 
         StringBuilder groupXML = new StringBuilder();
         GroupWriter.write(group, groupXML);
         log.debug("updateGroup: " + groupXML);
-        
-        HttpPost transfer = new HttpPost(updateGroupURL, groupXML.toString(), 
+
+        HttpPost transfer = new HttpPost(updateGroupURL, groupXML.toString(),
                                          "application/xml", true);
         transfer.setSSLSocketFactory(getSSLSocketFactory());
         transfer.run();
-        
+
         Throwable error = transfer.getThrowable();
         if (error != null)
         {
             // transfer returns a -1 code for anonymous access.
-            if ((transfer.getResponseCode() == -1) || 
-                (transfer.getResponseCode() == 401) || 
+            if ((transfer.getResponseCode() == -1) ||
+                (transfer.getResponseCode() == 401) ||
                 (transfer.getResponseCode() == 403))
             {
                 throw new AccessControlException(error.getMessage());
@@ -410,14 +465,19 @@ public class GMSClient
             }
             if (transfer.getResponseCode() == 404)
             {
-                if (error.getMessage() != null && error.getMessage().toLowerCase().contains("user"))
+                if (error.getMessage() != null && error.getMessage()
+                        .toLowerCase().contains("user"))
+                {
                     throw new UserNotFoundException(error.getMessage());
+                }
                 else
+                {
                     throw new GroupNotFoundException(error.getMessage());
+                }
             }
             throw new IOException(error);
         }
-        
+
         try
         {
             String retXML = transfer.getResponseBody();
@@ -440,15 +500,15 @@ public class GMSClient
      * @throws java.io.IOException
      */
     public void deleteGroup(String groupName)
-        throws GroupNotFoundException, AccessControlException, IOException
+            throws GroupNotFoundException, AccessControlException, IOException
     {
         URL deleteGroupURL = new URL(this.baseURL + "/groups/" + groupName);
         log.debug("deleteGroup request to " + deleteGroupURL.toString());
-        
+
         // reset the state of the cache
         clearCache();
 
-        HttpURLConnection conn = 
+        HttpURLConnection conn =
                 (HttpURLConnection) deleteGroupURL.openConnection();
         conn.setRequestMethod("DELETE");
 
@@ -465,19 +525,19 @@ public class GMSClient
         {
             responseCode = conn.getResponseCode();
         }
-        catch(Exception e)
+        catch (Exception e)
         {
             throw new AccessControlException(e.getMessage());
         }
-        
+
         if (responseCode != 200)
         {
             String errMessage = NetUtil.getErrorBody(conn);
-            log.debug("deleteGroup response " + responseCode + ": " + 
+            log.debug("deleteGroup response " + responseCode + ": " +
                       errMessage);
 
-            if ((responseCode == 401) || (responseCode == 403) || 
-                    (responseCode == -1))
+            if ((responseCode == 401) || (responseCode == 403) ||
+                (responseCode == -1))
             {
                 throw new AccessControlException(errMessage);
             }
@@ -499,19 +559,19 @@ public class GMSClient
      * @param targetGroupName The group in which to add the group member.
      * @param groupMemberName The group member to add.
      * @throws IllegalArgumentException If cyclical membership is detected.
-     * @throws GroupNotFoundException If the group was not found.
-     * @throws AccessControlException If unauthorized to perform this operation.
+     * @throws GroupNotFoundException   If the group was not found.
+     * @throws AccessControlException   If unauthorized to perform this operation.
      * @throws java.io.IOException
      */
     public void addGroupMember(String targetGroupName, String groupMemberName)
-        throws IllegalArgumentException, GroupNotFoundException,
-               AccessControlException, IOException
+            throws IllegalArgumentException, GroupNotFoundException,
+                   AccessControlException, IOException
     {
-        URL addGroupMemberURL = new URL(this.baseURL + "/groups/" + 
-                                        targetGroupName + "/groupMembers/" + 
+        URL addGroupMemberURL = new URL(this.baseURL + "/groups/" +
+                                        targetGroupName + "/groupMembers/" +
                                         groupMemberName);
         log.debug("addGroupMember request to " + addGroupMemberURL.toString());
-        
+
         // reset the state of the cache
         clearCache();
 
@@ -527,8 +587,8 @@ public class GMSClient
             final int responseCode = httpUpload.getResponseCode();
             final String errMessage = error.getMessage();
 
-            if ((responseCode == -1) || 
-                (responseCode == 401) || 
+            if ((responseCode == -1) ||
+                (responseCode == 401) ||
                 (responseCode == 403))
             {
                 throw new AccessControlException(errMessage);
@@ -549,23 +609,24 @@ public class GMSClient
      * Add a user as a member of a group.
      *
      * @param targetGroupName The group in which to add the group member.
-     * @param userID The user to add.
+     * @param userID          The user to add.
      * @throws GroupNotFoundException If the group was not found.
-     * @throws UserNotFoundException If the member was not found.
+     * @throws UserNotFoundException  If the member was not found.
      * @throws java.io.IOException
      * @throws AccessControlException If unauthorized to perform this operation.
      */
     public void addUserMember(String targetGroupName, Principal userID)
-        throws GroupNotFoundException, UserNotFoundException, AccessControlException, IOException
+            throws GroupNotFoundException, UserNotFoundException,
+                   AccessControlException, IOException
     {
         String userIDType = AuthenticationUtil.getPrincipalType(userID);
         String encodedUserID = URLEncoder.encode(userID.getName(), "UTF-8");
-        URL addUserMemberURL = new URL(this.baseURL + "/groups/" + 
-                                       targetGroupName + "/userMembers/" + 
+        URL addUserMemberURL = new URL(this.baseURL + "/groups/" +
+                                       targetGroupName + "/userMembers/" +
                                        encodedUserID + "?idType=" + userIDType);
 
         log.debug("addUserMember request to " + addUserMemberURL.toString());
-        
+
         // reset the state of the cache
         clearCache();
 
@@ -581,8 +642,8 @@ public class GMSClient
             final int responseCode = httpUpload.getResponseCode();
             final String errMessage = error.getMessage();
 
-            if ((responseCode == -1) || 
-                (responseCode == 401) || 
+            if ((responseCode == -1) ||
+                (responseCode == 401) ||
                 (responseCode == 403))
             {
                 throw new AccessControlException(errMessage);
@@ -593,10 +654,15 @@ public class GMSClient
             }
             if (responseCode == 404)
             {
-                if (errMessage != null && errMessage.toLowerCase().contains("user"))
+                if (errMessage != null && errMessage.toLowerCase()
+                        .contains("user"))
+                {
                     throw new UserNotFoundException(errMessage);
+                }
                 else
+                {
                     throw new GroupNotFoundException(errMessage);
+                }
             }
             throw new IOException(errMessage);
         }
@@ -611,20 +677,20 @@ public class GMSClient
      * @throws java.io.IOException
      * @throws AccessControlException If unauthorized to perform this operation.
      */
-    public void removeGroupMember(String targetGroupName, 
+    public void removeGroupMember(String targetGroupName,
                                   String groupMemberName)
-        throws GroupNotFoundException, AccessControlException, IOException
+            throws GroupNotFoundException, AccessControlException, IOException
     {
-        URL removeGroupMemberURL = new URL(this.baseURL + "/groups/" + 
-                                           targetGroupName + "/groupMembers/" + 
+        URL removeGroupMemberURL = new URL(this.baseURL + "/groups/" +
+                                           targetGroupName + "/groupMembers/" +
                                            groupMemberName);
-        log.debug("removeGroupMember request to " + 
+        log.debug("removeGroupMember request to " +
                   removeGroupMemberURL.toString());
-        
+
         // reset the state of the cache
         clearCache();
 
-        HttpURLConnection conn = 
+        HttpURLConnection conn =
                 (HttpURLConnection) removeGroupMemberURL.openConnection();
         conn.setRequestMethod("DELETE");
 
@@ -634,23 +700,25 @@ public class GMSClient
             ((HttpsURLConnection) conn)
                     .setSSLSocketFactory(getSSLSocketFactory());
         }
-        
+
         // Try to handle anonymous access and throw AccessControlException 
         int responseCode = -1;
         try
         {
             responseCode = conn.getResponseCode();
         }
-        catch (Exception ignore) {}
-        
+        catch (Exception ignore)
+        {
+        }
+
         if (responseCode != 200)
         {
             String errMessage = NetUtil.getErrorBody(conn);
-            log.debug("removeGroupMember response " + responseCode + ": " + 
+            log.debug("removeGroupMember response " + responseCode + ": " +
                       errMessage);
 
-            if ((responseCode == -1) || 
-                (responseCode == 401) || 
+            if ((responseCode == -1) ||
+                (responseCode == 401) ||
                 (responseCode == 403))
             {
                 throw new AccessControlException(errMessage);
@@ -671,29 +739,30 @@ public class GMSClient
      * Remove a user as a member of a group.
      *
      * @param targetGroupName The group from which to remove the group member.
-     * @param userID The user to remove.
+     * @param userID          The user to remove.
      * @throws GroupNotFoundException If the group was not found.
-     * @throws UserNotFoundException If the member was not found.
+     * @throws UserNotFoundException  If the member was not found.
      * @throws java.io.IOException
      * @throws AccessControlException If unauthorized to perform this operation.
      */
     public void removeUserMember(String targetGroupName, Principal userID)
-        throws GroupNotFoundException, UserNotFoundException, AccessControlException, IOException
+            throws GroupNotFoundException, UserNotFoundException,
+                   AccessControlException, IOException
     {
         String userIDType = AuthenticationUtil.getPrincipalType(userID);
         String encodedUserID = URLEncoder.encode(userID.toString(), "UTF-8");
-        URL removeUserMemberURL = new URL(this.baseURL + "/groups/" + 
-                                          targetGroupName + "/userMembers/" + 
-                                          encodedUserID + "?idType=" + 
+        URL removeUserMemberURL = new URL(this.baseURL + "/groups/" +
+                                          targetGroupName + "/userMembers/" +
+                                          encodedUserID + "?idType=" +
                                           userIDType);
 
         log.debug("removeUserMember request to " +
                   removeUserMemberURL.toString());
-        
+
         // reset the state of the cache
         clearCache();
 
-        HttpURLConnection conn = 
+        HttpURLConnection conn =
                 (HttpURLConnection) removeUserMemberURL.openConnection();
         conn.setRequestMethod("DELETE");
 
@@ -703,23 +772,25 @@ public class GMSClient
             ((HttpsURLConnection) conn)
                     .setSSLSocketFactory(getSSLSocketFactory());
         }
-        
+
         // Try to handle anonymous access and throw AccessControlException 
         int responseCode = -1;
         try
         {
             responseCode = conn.getResponseCode();
         }
-        catch (Exception ignore) {}
+        catch (Exception ignore)
+        {
+        }
 
         if (responseCode != 200)
         {
             String errMessage = NetUtil.getErrorBody(conn);
-            log.debug("removeUserMember response " + responseCode + ": " + 
+            log.debug("removeUserMember response " + responseCode + ": " +
                       errMessage);
 
-            if ((responseCode == -1) || 
-                (responseCode == 401) || 
+            if ((responseCode == -1) ||
+                (responseCode == 401) ||
                 (responseCode == 403))
             {
                 throw new AccessControlException(errMessage);
@@ -730,10 +801,15 @@ public class GMSClient
             }
             if (responseCode == 404)
             {
-                if (errMessage != null && errMessage.toLowerCase().contains("user"))
+                if (errMessage != null && errMessage.toLowerCase()
+                        .contains("user"))
+                {
                     throw new UserNotFoundException(errMessage);
+                }
                 else
+                {
                     throw new GroupNotFoundException(errMessage);
+                }
             }
             throw new IOException(errMessage);
         }
@@ -741,42 +817,42 @@ public class GMSClient
 
     /**
      * Get all the memberships of the user of a certain role.
-     * 
+     *
      * @param userID Identifies the user.
-     * @param role The role to look up.
+     * @param role   The role to look up.
      * @return A list of groups for which the user has the role.
-     * @throws UserNotFoundException If the user does not exist.
-     * @throws AccessControlException If not allowed to peform the search.
+     * @throws UserNotFoundException    If the user does not exist.
+     * @throws AccessControlException   If not allowed to peform the search.
      * @throws IllegalArgumentException If a parameter is null.
-     * @throws IOException If an unknown error occured.
+     * @throws IOException              If an unknown error occured.
      */
     public List<Group> getMemberships(Principal userID, Role role)
-        throws UserNotFoundException, AccessControlException, IOException
+            throws UserNotFoundException, AccessControlException, IOException
     {
         if (userID == null || role == null)
         {
             throw new IllegalArgumentException("userID and role are required.");
         }
-        
+
         List<Group> cachedGroups = getCachedGroups(userID, role);
         if (cachedGroups != null)
         {
             return cachedGroups;
         }
-        
+
         String idType = AuthenticationUtil.getPrincipalType(userID);
         String id = userID.getName();
         String roleString = role.getValue();
-        
+
         StringBuilder searchGroupURL = new StringBuilder(this.baseURL);
         searchGroupURL.append("/search?");
-        
+
         searchGroupURL.append("ID=").append(URLEncoder.encode(id, "UTF-8"));
         searchGroupURL.append("&IDTYPE=")
                 .append(URLEncoder.encode(idType, "UTF-8"));
         searchGroupURL.append("&ROLE=")
                 .append(URLEncoder.encode(roleString, "UTF-8"));
-        
+
         log.debug("getMemberships request to " + searchGroupURL.toString());
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         URL url = new URL(searchGroupURL.toString());
@@ -790,8 +866,8 @@ public class GMSClient
         {
             log.debug("getMemberships throwable", error);
             // transfer returns a -1 code for anonymous access.
-            if ((transfer.getResponseCode() == -1) || 
-                (transfer.getResponseCode() == 401) || 
+            if ((transfer.getResponseCode() == -1) ||
+                (transfer.getResponseCode() == 401) ||
                 (transfer.getResponseCode() == 403))
             {
                 throw new AccessControlException(error.getMessage());
@@ -821,50 +897,50 @@ public class GMSClient
             throw new RuntimeException(bug);
         }
     }
-    
+
     /**
      * Return the group, specified by paramter groupName, if the user,
      * identified by userID, is a member of that group.  Return null
      * otherwise.
-     * 
+     * <p/>
      * This call is identical to getMemberShip(userID, groupName, Role.MEMBER)
-     *  
-     * @param userID Identifies the user.
+     *
+     * @param userID    Identifies the user.
      * @param groupName Identifies the group.
      * @return The group or null of the user is not a member.
-     * @throws UserNotFoundException If the user does not exist.
-     * @throws AccessControlException If not allowed to peform the search.
+     * @throws UserNotFoundException    If the user does not exist.
+     * @throws AccessControlException   If not allowed to peform the search.
      * @throws IllegalArgumentException If a parameter is null.
-     * @throws IOException If an unknown error occured.
+     * @throws IOException              If an unknown error occured.
      */
     public Group getMembership(Principal userID, String groupName)
-        throws UserNotFoundException, AccessControlException, IOException
+            throws UserNotFoundException, AccessControlException, IOException
     {
         return getMembership(userID, groupName, Role.MEMBER);
     }
-    
+
     /**
      * Return the group, specified by paramter groupName, if the user,
      * identified by userID, is a member (of type role) of that group.
      * Return null otherwise.
-     * 
-     * @param userID Identifies the user.
+     *
+     * @param userID    Identifies the user.
      * @param groupName Identifies the group.
-     * @param role The membership role to search.
+     * @param role      The membership role to search.
      * @return The group or null of the user is not a member.
-     * @throws UserNotFoundException If the user does not exist.
-     * @throws AccessControlException If not allowed to peform the search.
+     * @throws UserNotFoundException    If the user does not exist.
+     * @throws AccessControlException   If not allowed to peform the search.
      * @throws IllegalArgumentException If a parameter is null.
-     * @throws IOException If an unknown error occured.
+     * @throws IOException              If an unknown error occured.
      */
     public Group getMembership(Principal userID, String groupName, Role role)
-        throws UserNotFoundException, AccessControlException, IOException
+            throws UserNotFoundException, AccessControlException, IOException
     {
         if (userID == null || groupName == null || role == null)
         {
             throw new IllegalArgumentException("userID and role are required.");
         }
-        
+
         List<Group> cachedGroups = getCachedGroups(userID, role);
         if (cachedGroups != null)
         {
@@ -878,11 +954,11 @@ public class GMSClient
                 return null;
             }
         }
-        
+
         String idType = AuthenticationUtil.getPrincipalType(userID);
         String id = userID.getName();
         String roleString = role.getValue();
-        
+
         StringBuilder searchGroupURL = new StringBuilder(this.baseURL);
         searchGroupURL.append("/search?");
 
@@ -893,7 +969,7 @@ public class GMSClient
                 .append(URLEncoder.encode(roleString, "UTF-8"));
         searchGroupURL.append("&GROUPID=")
                 .append(URLEncoder.encode(groupName, "UTF-8"));
-        
+
         log.debug("getMembership request to " + searchGroupURL.toString());
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         URL url = new URL(searchGroupURL.toString());
@@ -907,8 +983,8 @@ public class GMSClient
         {
             log.debug("getMembership throwable", error);
             // transfer returns a -1 code for anonymous access.
-            if ((transfer.getResponseCode() == -1) || 
-                (transfer.getResponseCode() == 401) || 
+            if ((transfer.getResponseCode() == -1) ||
+                (transfer.getResponseCode() == 401) ||
                 (transfer.getResponseCode() == 403))
             {
                 throw new AccessControlException(error.getMessage());
@@ -948,40 +1024,40 @@ public class GMSClient
             throw new RuntimeException(bug);
         }
     }
-    
+
     /**
      * Check if userID is a member of groupName.
-     * 
+     * <p/>
      * This is equivalent to isMember(userID, groupName, Role.MEMBER)
-     * 
-     * @param userID Identifies the user.
+     *
+     * @param userID    Identifies the user.
      * @param groupName Identifies the group.
      * @return True if the user is a member of the group
-     * @throws UserNotFoundException If the user does not exist.
-     * @throws AccessControlException If not allowed to peform the search.
+     * @throws UserNotFoundException    If the user does not exist.
+     * @throws AccessControlException   If not allowed to peform the search.
      * @throws IllegalArgumentException If a parameter is null.
-     * @throws IOException If an unknown error occured.
+     * @throws IOException              If an unknown error occured.
      */
     public boolean isMember(Principal userID, String groupName)
-        throws UserNotFoundException, AccessControlException, IOException
+            throws UserNotFoundException, AccessControlException, IOException
     {
         return isMember(userID, groupName, Role.MEMBER);
     }
-    
+
     /**
      * Check if userID is a member (of type role) of groupName.
-     * 
-     * @param userID Identifies the user.
+     *
+     * @param userID    Identifies the user.
      * @param groupName Identifies the group.
-     * @param role The type of membership.
+     * @param role      The type of membership.
      * @return True if the user is a member of the group
-     * @throws UserNotFoundException If the user does not exist.
-     * @throws AccessControlException If not allowed to peform the search.
+     * @throws UserNotFoundException    If the user does not exist.
+     * @throws AccessControlException   If not allowed to peform the search.
      * @throws IllegalArgumentException If a parameter is null.
-     * @throws IOException If an unknown error occured.
+     * @throws IOException              If an unknown error occured.
      */
     public boolean isMember(Principal userID, String groupName, Role role)
-        throws UserNotFoundException, AccessControlException, IOException
+            throws UserNotFoundException, AccessControlException, IOException
     {
         Group group = getMembership(userID, groupName, role);
         return group != null;
@@ -993,24 +1069,27 @@ public class GMSClient
     public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory)
     {
         if (mySocketFactory != null)
+        {
             throw new IllegalStateException("Illegal use of GMSClient: "
-                    + "cannot set SSLSocketFactory after using one created from Subject");
+                                            + "cannot set SSLSocketFactory after using one created from Subject");
+        }
         this.sslSocketFactory = sslSocketFactory;
         clearCache();
     }
-    
+
     private int subjectHashCode = 0;
+
     private SSLSocketFactory getSSLSocketFactory()
     {
         AccessControlContext ac = AccessController.getContext();
         Subject s = Subject.getSubject(ac);
-        
+
         // no real Subject: can only use the one from setSSLSocketFactory
         if (s == null || s.getPrincipals().isEmpty())
         {
             return sslSocketFactory;
         }
-        
+
         // lazy init
         if (this.mySocketFactory == null)
         {
@@ -1022,18 +1101,21 @@ public class GMSClient
         {
             int c = s.hashCode();
             if (c != subjectHashCode)
-                throw new IllegalStateException("Illegal use of " 
-                        + this.getClass().getSimpleName()
-                        + ": subject change not supported for internal SSLSocketFactory");
+            {
+                throw new IllegalStateException("Illegal use of "
+                                                + this.getClass()
+                                                        .getSimpleName()
+                                                + ": subject change not supported for internal SSLSocketFactory");
+            }
         }
         return this.mySocketFactory;
     }
-    
+
     protected void clearCache()
     {
         AccessControlContext acContext = AccessController.getContext();
         Subject subject = Subject.getSubject(acContext);
-        
+
         if (subject != null)
         {
             log.debug("Clearing cache");
@@ -1045,16 +1127,18 @@ public class GMSClient
     {
         AccessControlContext acContext = AccessController.getContext();
         Subject subject = Subject.getSubject(acContext);
-        
+
         // only consult cache if the userID is of the calling subject
         if (userIsSubject(userID, subject))
         {
-            Set groupCredentialSet = subject.getPrivateCredentials(GroupMemberships.class);
-            if ((groupCredentialSet != null) && 
+            Set groupCredentialSet = subject
+                    .getPrivateCredentials(GroupMemberships.class);
+            if ((groupCredentialSet != null) &&
                 (groupCredentialSet.size() == 1))
             {
                 Iterator i = groupCredentialSet.iterator();
-                GroupMemberships groupMemberships = ((GroupMemberships) i.next());
+                GroupMemberships groupMemberships = ((GroupMemberships) i
+                        .next());
                 return groupMemberships.memberships.get(role);
             }
         }
@@ -1065,15 +1149,16 @@ public class GMSClient
     {
         AccessControlContext acContext = AccessController.getContext();
         Subject subject = Subject.getSubject(acContext);
-        
+
         // only save to cache if the userID is of the calling subject
         if (userIsSubject(userID, subject))
         {
             log.debug("Caching groups for " + userID + ", role " + role);
-            
+
             final GroupMemberships groupCredentials;
-            Set groupCredentialSet = subject.getPrivateCredentials(GroupMemberships.class);
-            if ((groupCredentialSet != null) && 
+            Set groupCredentialSet = subject
+                    .getPrivateCredentials(GroupMemberships.class);
+            if ((groupCredentialSet != null) &&
                 (groupCredentialSet.size() == 1))
             {
                 Iterator i = groupCredentialSet.iterator();
@@ -1084,18 +1169,18 @@ public class GMSClient
                 groupCredentials = new GroupMemberships();
                 subject.getPrivateCredentials().add(groupCredentials);
             }
-            
-            groupCredentials.memberships.put(role,  groups);
+
+            groupCredentials.memberships.put(role, groups);
         }
     }
-    
+
     protected boolean userIsSubject(Principal userID, Subject subject)
     {
         if (userID == null || subject == null)
         {
             return false;
         }
-        
+
         for (Principal subjectPrincipal : subject.getPrincipals())
         {
             if (subjectPrincipal.equals(userID))
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/JSONUserListInputStreamWrapper.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/JSONUserListInputStreamWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e3a47447965467f2f822dc5a532fff1ab0571a0
--- /dev/null
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/JSONUserListInputStreamWrapper.java
@@ -0,0 +1,154 @@
+/*
+ ************************************************************************
+ *******************  CANADIAN ASTRONOMY DATA CENTRE  *******************
+ **************  CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES  **************
+ *
+ *  (c) 2015.                            (c) 2015.
+ *  Government of Canada                 Gouvernement du Canada
+ *  National Research Council            Conseil national de recherches
+ *  Ottawa, Canada, K1A 0R6              Ottawa, Canada, K1A 0R6
+ *  All rights reserved                  Tous droits réservés
+ *
+ *  NRC disclaims any warranties,        Le CNRC dénie toute garantie
+ *  expressed, implied, or               énoncée, implicite ou légale,
+ *  statutory, of any kind with          de quelque nature que ce
+ *  respect to the software,             soit, concernant le logiciel,
+ *  including without limitation         y compris sans restriction
+ *  any warranty of merchantability      toute garantie de valeur
+ *  or fitness for a particular          marchande ou de pertinence
+ *  purpose. NRC shall not be            pour un usage particulier.
+ *  liable in any event for any          Le CNRC ne pourra en aucun cas
+ *  damages, whether direct or           être tenu responsable de tout
+ *  indirect, special or general,        dommage, direct ou indirect,
+ *  consequential or incidental,         particulier ou général,
+ *  arising from the use of the          accessoire ou fortuit, résultant
+ *  software.  Neither the name          de l'utilisation du logiciel. Ni
+ *  of the National Research             le nom du Conseil National de
+ *  Council of Canada nor the            Recherches du Canada ni les noms
+ *  names of its contributors may        de ses  participants ne peuvent
+ *  be used to endorse or promote        être utilisés pour approuver ou
+ *  products derived from this           promouvoir les produits dérivés
+ *  software without specific prior      de ce logiciel sans autorisation
+ *  written permission.                  préalable et particulière
+ *                                       par écrit.
+ *
+ *  This file is part of the             Ce fichier fait partie du projet
+ *  OpenCADC project.                    OpenCADC.
+ *
+ *  OpenCADC is free software:           OpenCADC est un logiciel libre ;
+ *  you can redistribute it and/or       vous pouvez le redistribuer ou le
+ *  modify it under the terms of         modifier suivant les termes de
+ *  the GNU Affero General Public        la “GNU Affero General Public
+ *  License as published by the          License” telle que publiée
+ *  Free Software Foundation,            par la Free Software Foundation
+ *  either version 3 of the              : soit la version 3 de cette
+ *  License, or (at your option)         licence, soit (à votre gré)
+ *  any later version.                   toute version ultérieure.
+ *
+ *  OpenCADC is distributed in the       OpenCADC est distribué
+ *  hope that it will be useful,         dans l’espoir qu’il vous
+ *  but WITHOUT ANY WARRANTY;            sera utile, mais SANS AUCUNE
+ *  without even the implied             GARANTIE : sans même la garantie
+ *  warranty of MERCHANTABILITY          implicite de COMMERCIALISABILITÉ
+ *  or FITNESS FOR A PARTICULAR          ni d’ADÉQUATION À UN OBJECTIF
+ *  PURPOSE.  See the GNU Affero         PARTICULIER. Consultez la Licence
+ *  General Public License for           Générale Publique GNU Affero
+ *  more details.                        pour plus de détails.
+ *
+ *  You should have received             Vous devriez avoir reçu une
+ *  a copy of the GNU Affero             copie de la Licence Générale
+ *  General Public License along         Publique GNU Affero avec
+ *  with OpenCADC.  If not, see          OpenCADC ; si ce n’est
+ *  <http://www.gnu.org/licenses/>.      pas le cas, consultez :
+ *                                       <http://www.gnu.org/licenses/>.
+ *
+ *
+ ************************************************************************
+ */
+
+package ca.nrc.cadc.ac.client;
+
+import ca.nrc.cadc.ac.PersonalDetails;
+import ca.nrc.cadc.ac.User;
+import ca.nrc.cadc.auth.HttpPrincipal;
+import ca.nrc.cadc.net.InputStreamWrapper;
+import ca.nrc.cadc.util.StringUtil;
+import org.apache.log4j.Logger;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+
+public class JSONUserListInputStreamWrapper implements InputStreamWrapper
+{
+    private static final Logger LOGGER = Logger
+            .getLogger(JSONUserListInputStreamWrapper.class);
+    private final List<User<HttpPrincipal>> output;
+
+
+    public JSONUserListInputStreamWrapper(
+            final List<User<HttpPrincipal>> output)
+    {
+        this.output = output;
+    }
+
+
+    /**
+     * Read the stream in.
+     *
+     * @param inputStream The stream to read from.
+     * @throws IOException Any reading exceptions.
+     */
+    @Override
+    public void read(final InputStream inputStream) throws IOException
+    {
+        String line = null;
+
+        try
+        {
+            final InputStreamReader inReader =
+                    new InputStreamReader(inputStream);
+            final BufferedReader reader = new BufferedReader(inReader);
+
+            while (StringUtil.hasText(line = reader.readLine()))
+            {
+                // Deal with arrays stuff.
+                while (line.startsWith("[") || line.startsWith(","))
+                {
+                    line = line.substring(1);
+                }
+
+                while (line.endsWith("]") || line.endsWith(","))
+                {
+                    line = line.substring(0, (line.length() - 1));
+                }
+
+                if (StringUtil.hasText(line))
+                {
+                    LOGGER.debug(String.format("Reading: %s", line));
+
+                    final JSONObject jsonObject = new JSONObject(line);
+                    final User<HttpPrincipal> webUser =
+                            new User<HttpPrincipal>(
+                                    new HttpPrincipal(jsonObject
+                                                              .getString("id")));
+                    final String firstName = jsonObject.getString("firstName");
+                    final String lastName = jsonObject.getString("lastName");
+
+                    webUser.details
+                            .add(new PersonalDetails(firstName, lastName));
+
+                    output.add(webUser);
+                }
+            }
+        }
+        catch (Exception bug)
+        {
+            throw new IOException(bug + (StringUtil.hasText(line)
+                                         ? "Error line is " + line : ""));
+        }
+    }
+}
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/json/UsersWriter.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/json/UsersWriter.java
index 230559285f8a2349351a475015873035b39cc6f7..308148bcdadde1530c994bc1bea70a7a61f9cd14 100644
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/json/UsersWriter.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/json/UsersWriter.java
@@ -68,6 +68,7 @@
 
 package ca.nrc.cadc.ac.json;
 
+import ca.nrc.cadc.ac.PersonalDetails;
 import org.json.JSONException;
 import org.json.JSONWriter;
 
@@ -81,7 +82,7 @@ import java.util.Map;
  */
 public class UsersWriter
 {
-    public static void write(final Map<String, String> users,
+    public static void write(final Map<String, PersonalDetails> users,
                              final Writer writer) throws IOException
     {
         final JSONWriter jsonWriter = new JSONWriter(writer);
@@ -90,14 +91,19 @@ public class UsersWriter
         {
             jsonWriter.array();
 
-            for (final Map.Entry<String, String> entry : users.entrySet())
+            for (final Map.Entry<String, PersonalDetails> entry
+                    : users.entrySet())
             {
                 jsonWriter.object();
 
                 jsonWriter.key("id").value(entry.getKey());
-                jsonWriter.key("name").value(entry.getValue());
+                jsonWriter.key("firstName").value(entry.getValue().
+                        getFirstName());
+                jsonWriter.key("lastName").value(entry.getValue().
+                        getLastName());
 
                 jsonWriter.endObject();
+                writer.write("\n");
             }
         }
         catch (JSONException e)
@@ -112,7 +118,7 @@ public class UsersWriter
             }
             catch (JSONException e)
             {
-                throw new IOException(e);
+                // Do nothing.
             }
         }
     }
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UsersWriter.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UsersWriter.java
index f8584a468b14f2b23bef82632017f2192cf9f115..757af4901c0a2572ac563350ca76e142dd7d12ea 100644
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UsersWriter.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UsersWriter.java
@@ -68,6 +68,7 @@
 
 package ca.nrc.cadc.ac.xml;
 
+import ca.nrc.cadc.ac.PersonalDetails;
 import org.jdom2.Document;
 import org.jdom2.Element;
 import org.jdom2.output.Format;
@@ -86,21 +87,25 @@ public class UsersWriter
      * @param writer            The Writer to output to.
      * @throws IOException      Any writing errors.
      */
-    public static void write(final Map<String, String> users,
+    public static void write(final Map<String, PersonalDetails> users,
                              final Writer writer) throws IOException
     {
         // Create the root users Element.
         final Element usersElement = new Element("users");
 
-        for (final Map.Entry<String, String> entry : users.entrySet())
+        for (final Map.Entry<String, PersonalDetails> entry : users.entrySet())
         {
             final Element userEntryElement = new Element("user");
-            final Element nameElement = new Element("name");
+            final Element firstNameElement = new Element("firstName");
+            final Element lastNameElement = new Element("lastName");
 
             userEntryElement.setAttribute("id", entry.getKey());
 
-            nameElement.setText(entry.getValue());
-            userEntryElement.addContent(nameElement);
+            firstNameElement.setText(entry.getValue().getFirstName());
+            userEntryElement.addContent(firstNameElement);
+
+            lastNameElement.setText(entry.getValue().getLastName());
+            userEntryElement.addContent(lastNameElement);
 
             usersElement.addContent(userEntryElement);
         }
diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/GMSClientTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/GMSClientTest.java
index 3025fb37678ac4fc3d0f464e6b320f9ced4ebcaf..2da9b1e8948109ca172b198bf0e96965b54b6a7e 100644
--- a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/GMSClientTest.java
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/GMSClientTest.java
@@ -69,6 +69,7 @@
 
 package ca.nrc.cadc.ac.client;
 
+import java.io.IOException;
 import java.net.URI;
 import java.net.URL;
 import java.security.PrivilegedExceptionAction;
@@ -77,10 +78,10 @@ import java.util.List;
 
 import javax.security.auth.Subject;
 
+import ca.nrc.cadc.ac.User;
+import ca.nrc.cadc.net.HttpDownload;
 import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
-import org.junit.Assert;
-import org.junit.Test;
 
 import ca.nrc.cadc.ac.AC;
 import ca.nrc.cadc.ac.Group;
@@ -89,6 +90,11 @@ import ca.nrc.cadc.auth.HttpPrincipal;
 import ca.nrc.cadc.reg.client.RegistryClient;
 import ca.nrc.cadc.util.Log4jInit;
 
+import org.junit.Assert;
+import org.junit.Test;
+import static org.easymock.EasyMock.*;
+
+
 public class GMSClientTest
 {
     
@@ -98,7 +104,41 @@ public class GMSClientTest
     {
         Log4jInit.setLevel("ca.nrc.cadc.ac", Level.DEBUG);
     }
-    
+
+
+    @Test
+    public void testGetDisplayUsers() throws Exception
+    {
+        final HttpDownload mockHTTPDownload = createMock(HttpDownload.class);
+        final GMSClient testSubject = new GMSClient("http://mysite.com/users")
+        {
+            @Override
+            HttpDownload createDisplayUsersHTTPDownload(
+                    List<User<HttpPrincipal>> webUsers) throws IOException
+            {
+                return mockHTTPDownload;
+            }
+        };
+
+        mockHTTPDownload.setRequestProperty("Accept", "application/json");
+        expectLastCall().once();
+
+        mockHTTPDownload.run();
+        expectLastCall().once();
+
+        expect(mockHTTPDownload.getThrowable()).andReturn(null).once();
+
+        expect(mockHTTPDownload.getContentLength()).andReturn(88l).once();
+        expect(mockHTTPDownload.getContentType()).andReturn(
+                "application/json").once();
+
+        replay(mockHTTPDownload);
+
+        testSubject.getDisplayUsers();
+
+        verify(mockHTTPDownload);
+    }
+
     @Test
     public void testUserIsSubject()
     {
diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/JSONUserListInputStreamWrapperTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/JSONUserListInputStreamWrapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fe977e4e3e5120c17b8e407df7bc210767384099
--- /dev/null
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/JSONUserListInputStreamWrapperTest.java
@@ -0,0 +1,102 @@
+/*
+ ************************************************************************
+ *******************  CANADIAN ASTRONOMY DATA CENTRE  *******************
+ **************  CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES  **************
+ *
+ *  (c) 2015.                            (c) 2015.
+ *  Government of Canada                 Gouvernement du Canada
+ *  National Research Council            Conseil national de recherches
+ *  Ottawa, Canada, K1A 0R6              Ottawa, Canada, K1A 0R6
+ *  All rights reserved                  Tous droits réservés
+ *
+ *  NRC disclaims any warranties,        Le CNRC dénie toute garantie
+ *  expressed, implied, or               énoncée, implicite ou légale,
+ *  statutory, of any kind with          de quelque nature que ce
+ *  respect to the software,             soit, concernant le logiciel,
+ *  including without limitation         y compris sans restriction
+ *  any warranty of merchantability      toute garantie de valeur
+ *  or fitness for a particular          marchande ou de pertinence
+ *  purpose. NRC shall not be            pour un usage particulier.
+ *  liable in any event for any          Le CNRC ne pourra en aucun cas
+ *  damages, whether direct or           être tenu responsable de tout
+ *  indirect, special or general,        dommage, direct ou indirect,
+ *  consequential or incidental,         particulier ou général,
+ *  arising from the use of the          accessoire ou fortuit, résultant
+ *  software.  Neither the name          de l'utilisation du logiciel. Ni
+ *  of the National Research             le nom du Conseil National de
+ *  Council of Canada nor the            Recherches du Canada ni les noms
+ *  names of its contributors may        de ses  participants ne peuvent
+ *  be used to endorse or promote        être utilisés pour approuver ou
+ *  products derived from this           promouvoir les produits dérivés
+ *  software without specific prior      de ce logiciel sans autorisation
+ *  written permission.                  préalable et particulière
+ *                                       par écrit.
+ *
+ *  This file is part of the             Ce fichier fait partie du projet
+ *  OpenCADC project.                    OpenCADC.
+ *
+ *  OpenCADC is free software:           OpenCADC est un logiciel libre ;
+ *  you can redistribute it and/or       vous pouvez le redistribuer ou le
+ *  modify it under the terms of         modifier suivant les termes de
+ *  the GNU Affero General Public        la “GNU Affero General Public
+ *  License as published by the          License” telle que publiée
+ *  Free Software Foundation,            par la Free Software Foundation
+ *  either version 3 of the              : soit la version 3 de cette
+ *  License, or (at your option)         licence, soit (à votre gré)
+ *  any later version.                   toute version ultérieure.
+ *
+ *  OpenCADC is distributed in the       OpenCADC est distribué
+ *  hope that it will be useful,         dans l’espoir qu’il vous
+ *  but WITHOUT ANY WARRANTY;            sera utile, mais SANS AUCUNE
+ *  without even the implied             GARANTIE : sans même la garantie
+ *  warranty of MERCHANTABILITY          implicite de COMMERCIALISABILITÉ
+ *  or FITNESS FOR A PARTICULAR          ni d’ADÉQUATION À UN OBJECTIF
+ *  PURPOSE.  See the GNU Affero         PARTICULIER. Consultez la Licence
+ *  General Public License for           Générale Publique GNU Affero
+ *  more details.                        pour plus de détails.
+ *
+ *  You should have received             Vous devriez avoir reçu une
+ *  a copy of the GNU Affero             copie de la Licence Générale
+ *  General Public License along         Publique GNU Affero avec
+ *  with OpenCADC.  If not, see          OpenCADC ; si ce n’est
+ *  <http://www.gnu.org/licenses/>.      pas le cas, consultez :
+ *                                       <http://www.gnu.org/licenses/>.
+ *
+ *
+ ************************************************************************
+ */
+
+package ca.nrc.cadc.ac.client;
+
+import ca.nrc.cadc.ac.User;
+import ca.nrc.cadc.auth.HttpPrincipal;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+
+public class JSONUserListInputStreamWrapperTest
+{
+    @Test
+    public void readInputStream() throws Exception
+    {
+        final List<User<HttpPrincipal>> output =
+                new ArrayList<User<HttpPrincipal>>();
+        final JSONUserListInputStreamWrapper testSubject =
+                new JSONUserListInputStreamWrapper(output);
+        final InputStream inputStream =
+                new ByteArrayInputStream("[{\"id\":\"CADCTest\",\"firstName\":\"CADCtest\",\"lastName\":\"USER\"}\n,{\"id\":\"User_2\",\"firstName\":\"User\",\"lastName\":\"2\"}]".getBytes());
+
+        testSubject.read(inputStream);
+
+        assertEquals("First item is wrong.", "CADCTest",
+                     output.get(0).getUserID().getName());
+        assertEquals("First item is wrong.", "User_2",
+                     output.get(1).getUserID().getName());
+    }
+}