From f8e1a0fea943c033b47552d9ab28bfde9ea81fd6 Mon Sep 17 00:00:00 2001 From: Dustin Jenkins <Dustin.Jenkins@nrc-cnrc.gc.ca> Date: Thu, 23 Jul 2015 15:08:12 -0700 Subject: [PATCH] AC2: Implement whoami entry. --- .../nrc/cadc/ac/server/UserPersistence.java | 7 +- .../nrc/cadc/ac/server/ldap/LdapUserDAO.java | 23 +- .../ac/server/ldap/LdapUserPersistence.java | 7 +- .../cadc/ac/server/web/users/UsersAction.java | 3 +- .../server/web/users/GetUsersActionTest.java | 30 +- .../src/ca/nrc/cadc/ac/client/GMSClient.java | 461 +++++++++++------- .../JSONUserListInputStreamWrapper.java | 154 ++++++ .../src/ca/nrc/cadc/ac/json/UsersWriter.java | 14 +- .../src/ca/nrc/cadc/ac/xml/UsersWriter.java | 15 +- .../ca/nrc/cadc/ac/client/GMSClientTest.java | 46 +- .../JSONUserListInputStreamWrapperTest.java | 102 ++++ 11 files changed, 633 insertions(+), 229 deletions(-) create mode 100644 projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/JSONUserListInputStreamWrapper.java create mode 100644 projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/JSONUserListInputStreamWrapperTest.java 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 b2730be0..380961d8 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 fe3aba9a..b6a89998 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 @@ -424,15 +424,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}; @@ -450,10 +451,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 452598a1..af766246 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 60f75a3e..ce700e16 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/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 e8f7004f..f1dc7a29 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 159e48ea..8f4eab02 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 00000000..8e3a4744 --- /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 23055928..308148bc 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 f8584a46..757af490 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 3025fb37..2da9b1e8 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 00000000..fe977e4e --- /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()); + } +} -- GitLab