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 759e413e165e11ca1698eba743e2e5e6c2737212..00bb7c81e031285a2af2fe12e7a969d26f12e7a8 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java
@@ -84,7 +84,6 @@ import java.security.AccessController;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -93,13 +92,10 @@ 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 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.Role;
-import ca.nrc.cadc.ac.UserNotFoundException;
 import ca.nrc.cadc.ac.xml.GroupListReader;
 import ca.nrc.cadc.ac.xml.GroupReader;
 import ca.nrc.cadc.ac.xml.GroupWriter;
@@ -183,6 +179,68 @@ public class GMSClient implements TransferListener
         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);
+            }
+            else
+            {
+                throw new IOException("HttpResponse (" + responseCode + ") - "
+                                      + errMessage);
+            }
+        }
+
+        log.debug("Content-Length: " + httpDownload.getContentLength());
+        log.debug("Content-Type: " + httpDownload.getContentType());
+
+        return webUsers;
+    }
+
+
+    /**
+     * Create a new HTTPDownload instance.  Testers can override as needed.
+     *
+     * @param webUsers          The User objects.
+     * @return                  HttpDownload instance.  Never null.
+     * @throws IOException      Any writing/reading errors.
+     */
+    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.
      *
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/client/JsonUserListInputStreamWrapper.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapper.java
index f00b0aeef2821f4740ae2eab7130b33d0001009f..8e3a47447965467f2f822dc5a532fff1ab0571a0 100644
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapper.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapper.java
@@ -82,15 +82,15 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.List;
 
-public class JsonUserListInputStreamWrapper implements InputStreamWrapper
+public class JSONUserListInputStreamWrapper implements InputStreamWrapper
 {
     private static final Logger LOGGER = Logger
-            .getLogger(JsonUserListInputStreamWrapper.class);
+            .getLogger(JSONUserListInputStreamWrapper.class);
     private final List<User<HttpPrincipal>> output;
 
 
-    public JsonUserListInputStreamWrapper(
-        final List<User<HttpPrincipal>> output)
+    public JSONUserListInputStreamWrapper(
+            final List<User<HttpPrincipal>> output)
     {
         this.output = output;
     }
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 9bf89c7fff88d9ef792fbe0eaf873cc088a53e38..d3eade86bb389c2368c7c6c16082f2f0a197b18c 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
@@ -92,6 +92,7 @@ import ca.nrc.cadc.util.Log4jInit;
 
 import org.junit.Assert;
 import org.junit.Test;
+
 import static org.easymock.EasyMock.*;
 
 
@@ -105,6 +106,37 @@ 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()
     {
@@ -151,52 +183,58 @@ public class GMSClientTest
 
             RegistryClient regClient = new RegistryClient();
             URL baseURL = regClient.getServiceURL(new URI(AC.GMS_SERVICE_URI),
-                    "https");
+                                                  "https");
             final GMSClient client = new GMSClient(baseURL.toString());
 
             Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
+            {
+                @Override
+                public Object run() throws Exception
                 {
-                    @Override
-                    public Object run() throws Exception
-                    {
-
-                        List<Group> initial = client.getCachedGroups(test1UserID, Role.MEMBER, true);
-                        Assert.assertNull("Cache should be null", initial);
 
-                        // add single group as isMember might do
-                        Group group0 = new Group("0");
-                        client.addCachedGroup(test1UserID, group0, Role.MEMBER);
-                        List<Group> actual = client.getCachedGroups(test1UserID, Role.MEMBER, true);
-                        Assert.assertNull("Cache should be null", actual);
-
-                        Group g = client.getCachedGroup(test1UserID, "0", Role.MEMBER);
-                        Assert.assertNotNull("cached group from incomplete cache", g);
-
-                        // add all groups like getMemberships might do
-                        List<Group> expected = new ArrayList<Group>();
-                        Group group1 = new Group("1");
-                        Group group2 = new Group("2");
-                        expected.add(group0);
-                        expected.add(group1);
-                        expected.add(group2);
-
-                        client.setCachedGroups(test1UserID, expected, Role.MEMBER);
-
-                        actual = client.getCachedGroups(test1UserID, Role.MEMBER, true);
-                        Assert.assertEquals("Wrong cached groups", expected, actual);
-
-                        // check against another role
-                        actual = client.getCachedGroups(test1UserID, Role.OWNER, true);
-                        Assert.assertNull("Cache should be null", actual);
-
-                        // check against another userid
-                        final HttpPrincipal anotherUserID = new HttpPrincipal("anotheruser");
-                        actual = client.getCachedGroups(anotherUserID, Role.MEMBER, true);
-                        Assert.assertNull("Cache should be null", actual);
-
-                        return null;
-                    }
-                });
+                    List<Group> initial = client
+                            .getCachedGroups(test1UserID, Role.MEMBER, true);
+                    Assert.assertNull("Cache should be null", initial);
+
+                    // add single group as isMember might do
+                    Group group0 = new Group("0");
+                    client.addCachedGroup(test1UserID, group0, Role.MEMBER);
+                    List<Group> actual = client
+                            .getCachedGroups(test1UserID, Role.MEMBER, true);
+                    Assert.assertNull("Cache should be null", actual);
+
+                    Group g = client
+                            .getCachedGroup(test1UserID, "0", Role.MEMBER);
+                    Assert.assertNotNull("cached group from incomplete cache", g);
+
+                    // add all groups like getMemberships might do
+                    List<Group> expected = new ArrayList<Group>();
+                    Group group1 = new Group("1");
+                    Group group2 = new Group("2");
+                    expected.add(group0);
+                    expected.add(group1);
+                    expected.add(group2);
+
+                    client.setCachedGroups(test1UserID, expected, Role.MEMBER);
+
+                    actual = client
+                            .getCachedGroups(test1UserID, Role.MEMBER, true);
+                    Assert.assertEquals("Wrong cached groups", expected, actual);
+
+                    // check against another role
+                    actual = client
+                            .getCachedGroups(test1UserID, Role.OWNER, true);
+                    Assert.assertNull("Cache should be null", actual);
+
+                    // check against another userid
+                    final HttpPrincipal anotherUserID = new HttpPrincipal("anotheruser");
+                    actual = client
+                            .getCachedGroups(anotherUserID, Role.MEMBER, true);
+                    Assert.assertNull("Cache should be null", actual);
+
+                    return null;
+                }
+            });
 
             subject = new Subject();
             final HttpPrincipal test2UserID = new HttpPrincipal("test2");
@@ -204,41 +242,46 @@ public class GMSClientTest
 
             // do the same but as a different user
             Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
-                    {
-                        @Override
-                        public Object run() throws Exception
-                        {
+            {
+                @Override
+                public Object run() throws Exception
+                {
 
-                            List<Group> initial = client.getCachedGroups(test2UserID, Role.MEMBER, true);
-                            Assert.assertNull("Cache should be null", initial);
+                    List<Group> initial = client
+                            .getCachedGroups(test2UserID, Role.MEMBER, true);
+                    Assert.assertNull("Cache should be null", initial);
 
-                            List<Group> expected = new ArrayList<Group>();
-                            Group group1 = new Group("1");
-                            Group group2 = new Group("2");
-                            expected.add(group1);
-                            expected.add(group2);
+                    List<Group> expected = new ArrayList<Group>();
+                    Group group1 = new Group("1");
+                    Group group2 = new Group("2");
+                    expected.add(group1);
+                    expected.add(group2);
 
-                            client.setCachedGroups(test2UserID, expected, Role.MEMBER);
+                    client.setCachedGroups(test2UserID, expected, Role.MEMBER);
 
-                            List<Group> actual = client.getCachedGroups(test2UserID, Role.MEMBER, true);
-                            Assert.assertEquals("Wrong cached groups", expected, actual);
+                    List<Group> actual = client
+                            .getCachedGroups(test2UserID, Role.MEMBER, true);
+                    Assert.assertEquals("Wrong cached groups", expected, actual);
 
-                            // check against another role
-                            actual = client.getCachedGroups(test2UserID, Role.OWNER, true);
-                            Assert.assertNull("Cache should be null", actual);
+                    // check against another role
+                    actual = client
+                            .getCachedGroups(test2UserID, Role.OWNER, true);
+                    Assert.assertNull("Cache should be null", actual);
 
-                            // check against another userid
-                            final HttpPrincipal anotherUserID = new HttpPrincipal("anotheruser");
-                            actual = client.getCachedGroups(anotherUserID, Role.MEMBER, true);
-                            Assert.assertNull("Cache should be null", actual);
+                    // check against another userid
+                    final HttpPrincipal anotherUserID = new HttpPrincipal("anotheruser");
+                    actual = client
+                            .getCachedGroups(anotherUserID, Role.MEMBER, true);
+                    Assert.assertNull("Cache should be null", actual);
 
-                            return null;
-                        }
-                    });
+                    return null;
+                }
+            });
 
             // do the same without a subject
 
-            List<Group> initial = client.getCachedGroups(test1UserID, Role.MEMBER, true);
+            List<Group> initial = client
+                    .getCachedGroups(test1UserID, Role.MEMBER, true);
             Assert.assertNull("Cache should be null", initial);
 
             List<Group> newgroups = new ArrayList<Group>();
@@ -249,7 +292,8 @@ public class GMSClientTest
 
             client.setCachedGroups(test1UserID, newgroups, Role.MEMBER);
 
-            List<Group> actual = client.getCachedGroups(test1UserID, Role.MEMBER, true);
+            List<Group> actual = client
+                    .getCachedGroups(test1UserID, Role.MEMBER, true);
             Assert.assertNull("Cache should still be null", actual);
         }
         catch (Throwable t)
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
index d8bd34ea6a1aae47bc8b0bd4b7182f3838932329..fe977e4e3e5120c17b8e407df7bc210767384099 100644
--- a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapperTest.java
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapperTest.java
@@ -80,15 +80,15 @@ import org.junit.Test;
 import static org.junit.Assert.*;
 
 
-public class JsonUserListInputStreamWrapperTest
+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 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());