diff --git a/projects/cadcAccessControl-Server/build.xml b/projects/cadcAccessControl-Server/build.xml index c4e48687ff5f6e922ab5fa54e6d58b319efff02b..12e688469aee1444d7027bef89f048af9de33f88 100644 --- a/projects/cadcAccessControl-Server/build.xml +++ b/projects/cadcAccessControl-Server/build.xml @@ -138,4 +138,20 @@ value="${ext.lib}/commons-logging.jar"/> <property name="testingJars" value="${lib.commons-logging}:${dev.junit}:${dev.jsonassert}:${dev.httpunit}:${dev.easyMock}:${dev.selenium.server}:${dev.objenesis}:${lib.js}:${lib.nekoHTML}:${lib.xerces}"/> + + <target name="test" depends="compile,compile-test"> + <echo message="Running test suite..." /> + <junit printsummary="yes" haltonfailure="yes" fork="yes"> + <classpath> + <pathelement path="${build}/class"/> + <pathelement path="${build}/test/class"/> + <pathelement path="${jars}:${testingJars}"/> + </classpath> + <sysproperty key="ca.nrc.cadc.util.PropertiesReader.dir" value="test"/> + <test name="ca.nrc.cadc.ac.server.ldap.LdapUserDAOTest" /> + <test name="ca.nrc.cadc.ac.server.ldap.LdapGroupDAOTest" /> + <formatter type="plain" usefile="false" /> + </junit> + </target> + </project> diff --git a/projects/cadcAccessControl-Server/config/LdapConfig.dev.properties b/projects/cadcAccessControl-Server/config/LdapConfig.dev.properties new file mode 100644 index 0000000000000000000000000000000000000000..0612a33b3987c7efbc6f19c01fb1b4d72efec14a --- /dev/null +++ b/projects/cadcAccessControl-Server/config/LdapConfig.dev.properties @@ -0,0 +1,13 @@ +# 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 = 636 +proxyUser = testproxy +usersDn = ou=Users,ou=ds,dc=testcanfar +userRequestsDN = ou=UserRequests,ou=ds,dc=testcanfar +groupsDn = ou=Groups,ou=ds,dc=testcanfar +adminGroupsDn = ou=adminGroups,ou=ds,dc=testcanfar \ No newline at end of file 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/LdapDAO.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java index 1b85d39d0a180638f3d53bb03b21449960f35d7f..528a44dedad746a1e02cda2e564016361fcf4aa2 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java @@ -68,7 +68,6 @@ */ package ca.nrc.cadc.ac.server.ldap; -import ca.nrc.cadc.ac.UserAlreadyExistsException; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.auth.OpenIdPrincipal; @@ -79,18 +78,17 @@ import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.ResultCode; import com.unboundid.ldap.sdk.SearchResult; import com.unboundid.ldap.sdk.SearchScope; +import org.apache.log4j.Logger; -import java.nio.file.FileAlreadyExistsException; +import javax.net.SocketFactory; +import javax.net.ssl.SSLSocketFactory; +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; import java.security.AccessControlException; import java.security.AccessController; import java.security.GeneralSecurityException; import java.security.Principal; import java.util.Set; -import javax.net.SocketFactory; -import javax.net.ssl.SSLSocketFactory; -import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; -import org.apache.log4j.Logger; public abstract class LdapDAO @@ -236,6 +234,7 @@ public abstract class LdapDAO throws TransientException { logger.debug("Ldap result: " + code); + System.out.println("Ldap result: " + code); if (code == ResultCode.INSUFFICIENT_ACCESS_RIGHTS) { diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java index 23ad3b9a6cbc0728423df19a7028ffb58b24baa3..726b5f94cfda210c83e26d7f46327d29268f1baa 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java @@ -68,18 +68,6 @@ */ package ca.nrc.cadc.ac.server.ldap; -import java.security.AccessControlException; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.security.auth.x500.X500Principal; - -import org.apache.log4j.Logger; - import ca.nrc.cadc.ac.ActivatedGroup; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupAlreadyExistsException; @@ -89,7 +77,6 @@ import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.util.StringUtil; - import com.unboundid.ldap.sdk.AddRequest; import com.unboundid.ldap.sdk.Attribute; import com.unboundid.ldap.sdk.DN; @@ -106,6 +93,16 @@ import com.unboundid.ldap.sdk.SearchResult; import com.unboundid.ldap.sdk.SearchResultEntry; import com.unboundid.ldap.sdk.SearchScope; import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl; +import org.apache.log4j.Logger; + +import javax.security.auth.x500.X500Principal; +import java.security.AccessControlException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class LdapGroupDAO<T extends Principal> extends LdapDAO { 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 fe3aba9a3c980198c512514e18d7582c3d3e16e1..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 @@ -68,23 +68,41 @@ */ package ca.nrc.cadc.ac.server.ldap; -import ca.nrc.cadc.ac.*; +import ca.nrc.cadc.ac.PersonalDetails; +import ca.nrc.cadc.ac.PosixDetails; +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserAlreadyExistsException; +import ca.nrc.cadc.ac.UserDetails; +import ca.nrc.cadc.ac.UserNotFoundException; +import ca.nrc.cadc.ac.UserRequest; import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; import com.unboundid.ldap.sdk.AddRequest; import com.unboundid.ldap.sdk.Attribute; +import com.unboundid.ldap.sdk.BindRequest; +import com.unboundid.ldap.sdk.BindResult; +import com.unboundid.ldap.sdk.Control; import com.unboundid.ldap.sdk.DN; import com.unboundid.ldap.sdk.Filter; import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.LDAPResult; import com.unboundid.ldap.sdk.LDAPSearchException; +import com.unboundid.ldap.sdk.Modification; +import com.unboundid.ldap.sdk.ModificationType; +import com.unboundid.ldap.sdk.ModifyRequest; import com.unboundid.ldap.sdk.ResultCode; import com.unboundid.ldap.sdk.SearchRequest; import com.unboundid.ldap.sdk.SearchResult; import com.unboundid.ldap.sdk.SearchResultEntry; import com.unboundid.ldap.sdk.SearchScope; +import com.unboundid.ldap.sdk.SimpleBindRequest; import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl; +import com.unboundid.ldap.sdk.extensions.PasswordModifyExtendedRequest; +import com.unboundid.ldap.sdk.extensions.PasswordModifyExtendedResult; +import org.apache.log4j.Logger; + +import javax.security.auth.x500.X500Principal; import java.security.AccessControlException; import java.security.Principal; import java.util.ArrayList; @@ -93,8 +111,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import javax.security.auth.x500.X500Principal; -import org.apache.log4j.Logger; public class LdapUserDAO<T extends Principal> extends LdapDAO @@ -108,7 +124,6 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO protected static final String LDAP_OBJECT_CLASS = "objectClass"; protected static final String LDAP_INET_ORG_PERSON = "inetOrgPerson"; protected static final String LDAP_CADC_ACCOUNT = "cadcaccount"; - protected static final String LDAP_POSIX_ACCOUNT = "posixaccount"; protected static final String LDAP_NSACCOUNTLOCK = "nsaccountlock"; protected static final String LDAP_MEMBEROF = "memberOf"; protected static final String LDAP_ENTRYDN = "entrydn"; @@ -123,18 +138,12 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO protected static final String LDAP_EMAIL = "email"; protected static final String LDAP_INSTITUTE = "institute"; protected static final String LDAP_UID = "uid"; - protected static final String LDAP_UID_NUMBER = "uidNumber"; - protected static final String LDAP_GID_NUMBER = "gidNumber"; - protected static final String LDAP_HOME_DIRECTORY = "homeDirectory"; - protected static final String LDAP_LOGIN_SHELL = "loginShell"; private String[] userAttribs = new String[] { LDAP_FIRST_NAME, LDAP_LAST_NAME, LDAP_ADDRESS, LDAP_CITY, LDAP_COUNTRY, - LDAP_EMAIL, LDAP_INSTITUTE, LDAP_UID, LDAP_UID_NUMBER, - LDAP_GID_NUMBER, - LDAP_HOME_DIRECTORY, LDAP_LOGIN_SHELL + LDAP_EMAIL, LDAP_INSTITUTE, LDAP_UID }; private String[] memberAttribs = new String[] { @@ -163,6 +172,40 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO memberAttribs = tmp; } + /** + * Verifies the username and password for an existing User. + * + * @param username username to verify. + * @param password password to verify. + * @return User + * @throws TransientException + * @throws UserNotFoundException + */ + public User<T> loginUser(final String username, final String password) + throws TransientException, UserNotFoundException + { + try + { + BindRequest bindRequest = new SimpleBindRequest(getUserDN(username), password); + BindResult bindResult = getConnection().bind(bindRequest); + + if (bindResult != null && bindResult.getResultCode() == ResultCode.SUCCESS) + { + return getUser((T) new HttpPrincipal(username)); + } + else + { + throw new AccessControlException("Invalid username or password"); + } + } + catch (LDAPException e) + { + logger.debug("addUser Exception: " + e, e); + + throw new RuntimeException("Unexpected LDAP exception", e); + } + } + /** * @return * @throws TransientException @@ -201,17 +244,15 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO return userIDs; } - catch (LDAPException e1) + catch (LDAPException e) { - logger.debug("getCadcIDs Exception: " + e1, e1); - LdapDAO.checkLdapResult(e1.getResultCode()); + logger.error("getCadcIDs Exception: " + e, e); + LdapDAO.checkLdapResult(e.getResultCode()); throw new IllegalStateException("Unexpected exception: " + - e1.getMatchedDN(), e1); + e.getMatchedDN(), e); } - } - /** * Add the specified user.. * @@ -223,6 +264,70 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO */ public User<T> addUser(final UserRequest<T> userRequest) throws TransientException, UserAlreadyExistsException + { + DN userDN; + try + { + userDN = getUserRequestsDN(userRequest.getUser().getUserID().getName()); + addUser(userRequest, userDN); + + // AD: Search results sometimes come incomplete if + // connection is not reset - not sure why. + getConnection().reconnect(); + try + { + return getUser(userRequest.getUser().getUserID(), config.getUserRequestsDN()); + } + catch (UserNotFoundException e) + { + throw new RuntimeException("BUG: new user " + userDN.toNormalizedString() + + " not found because " + e.getMessage()); + } + } + catch (LDAPException e) + { + logger.error("addUser Exception: " + e, e); + LdapUserDAO.checkUserLDAPResult(e.getResultCode()); + throw new RuntimeException("Unexpected LDAP exception", e); + } + } + + /** + * Package level method for unit testing to add a User directly to the + * Users tree. + */ + User<T> newUser(final UserRequest<T> userRequest) + throws TransientException, UserAlreadyExistsException + { + DN userDN; + try + { + userDN = getUserDN(userRequest.getUser().getUserID().getName()); + addUser(userRequest, userDN); + + // AD: Search results sometimes come incomplete if + // connection is not reset - not sure why. + getConnection().reconnect(); + try + { + return getUser(userRequest.getUser().getUserID(), config.getUsersDN()); + } + catch (UserNotFoundException e) + { + throw new RuntimeException("BUG: new user " + userDN.toNormalizedString() + + " not found because " + e.getMessage()); + } + } + catch (LDAPException e) + { + logger.error("newUser Exception: " + e, e); + LdapUserDAO.checkUserLDAPResult(e.getResultCode()); + throw new RuntimeException("Unexpected LDAP exception", e); + } + } + + private void addUser(final UserRequest<T> userRequest, final DN userDN) + throws TransientException, UserAlreadyExistsException { final User<T> user = userRequest.getUser(); final Class userType = user.getUserID().getClass(); @@ -236,24 +341,22 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO try { // add new user - DN userDN = getUserRequestsDN(user.getUserID().getName()); List<Attribute> attributes = new ArrayList<Attribute>(); addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_INET_ORG_PERSON); addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_CADC_ACCOUNT); addAttribute(attributes, LDAP_COMMON_NAME, user.getUserID() - .getName()); + .getName()); addAttribute(attributes, LDAP_DISTINGUISHED_NAME, userDN - .toNormalizedString()); + .toNormalizedString()); addAttribute(attributes, LADP_USER_PASSWORD, userRequest - .getPassword()); + .getPassword()); for (UserDetails details : user.details) { if (details.getClass() == PersonalDetails.class) { PersonalDetails pd = (PersonalDetails) details; - addAttribute(attributes, LDAP_FIRST_NAME, pd - .getFirstName()); + addAttribute(attributes, LDAP_FIRST_NAME, pd.getFirstName()); addAttribute(attributes, LDAP_LAST_NAME, pd.getLastName()); addAttribute(attributes, LDAP_ADDRESS, pd.address); addAttribute(attributes, LDAP_CITY, pd.city); @@ -263,44 +366,18 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO } else if (details.getClass() == PosixDetails.class) { - PosixDetails pd = (PosixDetails) details; - addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_POSIX_ACCOUNT); - addAttribute(attributes, LDAP_UID, Long - .toString(pd.getUid())); - addAttribute(attributes, LDAP_UID_NUMBER, Long - .toString(pd.getUid())); - addAttribute(attributes, LDAP_GID_NUMBER, Long - .toString(pd.getGid())); - addAttribute(attributes, LDAP_HOME_DIRECTORY, pd - .getHomeDirectory()); - addAttribute(attributes, LDAP_LOGIN_SHELL, pd.loginShell); + throw new UnsupportedOperationException( + "Support for users PosixDetails not available"); } } AddRequest addRequest = new AddRequest(userDN, attributes); LDAPResult result = getConnection().add(addRequest); LdapDAO.checkLdapResult(result.getResultCode()); - - // AD: Search results sometimes come incomplete if - // connection is not reset - not sure why. - getConnection().reconnect(); - try - { - return getUser(user.getUserID(), config.getUserRequestsDN()); - } - catch (UserNotFoundException e) - { - throw new RuntimeException("BUG: new user " + userDN - .toNormalizedString() + - " not found, result " + result - .getResultCode()); - } } catch (LDAPException e) { - System.out.println("LDAPe: " + e); - System.out.println("LDAPrc: " + e.getResultCode()); - logger.debug("addUser Exception: " + e, e); + logger.error("addUser Exception: " + e, e); LdapUserDAO.checkUserLDAPResult(e.getResultCode()); throw new RuntimeException("Unexpected LDAP exception", e); } @@ -376,9 +453,8 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO throw new UserNotFoundException(msg); } User<T> user = new User<T>(userID); - user.getIdentities().add(new HttpPrincipal(searchResult - .getAttributeValue(userLdapAttrib - .get(HttpPrincipal.class)))); + user.getIdentities().add(new HttpPrincipal(searchResult.getAttributeValue( + userLdapAttrib.get(HttpPrincipal.class)))); String fname = searchResult.getAttributeValue(LDAP_FIRST_NAME); String lname = searchResult.getAttributeValue(LDAP_LAST_NAME); @@ -391,18 +467,6 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO .getAttributeValue(LDAP_INSTITUTE); user.details.add(personaDetails); - Long uid = searchResult.getAttributeValueAsLong(LDAP_UID_NUMBER); - Long gid = searchResult.getAttributeValueAsLong(LDAP_GID_NUMBER); - String homeDirectory = searchResult - .getAttributeValue(LDAP_HOME_DIRECTORY); - if (uid != null && gid != null && homeDirectory != null) - { - PosixDetails posixDetails = new PosixDetails(uid, gid, homeDirectory); - posixDetails.loginShell = searchResult - .getAttributeValue(LDAP_LOGIN_SHELL); - user.details.add(posixDetails); - } - return user; } @@ -424,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}; @@ -450,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)); } } } @@ -487,11 +558,95 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public User<T> modifyUser(User<T> user) - throws UserNotFoundException, TransientException, - AccessControlException + public User<T> modifyUser(final User<T> user) + throws UserNotFoundException, TransientException, AccessControlException { - return null; + User existingUser = getUser(user.getUserID()); + + List<Modification> mods = new ArrayList<Modification>(); + for (UserDetails details : user.details) + { + if (details.getClass() == PersonalDetails.class) + { + PersonalDetails pd = (PersonalDetails) details; + addModification(mods, LDAP_FIRST_NAME, pd.getFirstName()); + addModification(mods, LDAP_LAST_NAME, pd.getLastName()); + addModification(mods, LDAP_ADDRESS, pd.address); + addModification(mods, LDAP_CITY, pd.city); + addModification(mods, LDAP_COUNTRY, pd.country); + addModification(mods, LDAP_EMAIL, pd.email); + addModification(mods, LDAP_INSTITUTE, pd.institute); + } + else if (details.getClass() == PosixDetails.class) + { + throw new UnsupportedOperationException( + "Support for users PosixDetails not available"); + } + } + + try + { + ModifyRequest modifyRequest = new ModifyRequest(getUserDN(user), mods); + modifyRequest.addControl( + new ProxiedAuthorizationV2RequestControl( + "dn:" + getSubjectDN().toNormalizedString())); + LdapDAO.checkLdapResult(getConnection().modify(modifyRequest).getResultCode()); + } + catch (LDAPException e) + { + e.printStackTrace(); + logger.debug("Modify Exception: " + e, e); + LdapDAO.checkLdapResult(e.getResultCode()); + } + try + { + return getUser(user.getUserID()); + } + catch (UserNotFoundException e) + { + throw new RuntimeException( + "BUG: modified user not found (" + user.getUserID() + ")"); + } + } + + /** + * Update a user's password. The given user and authenticating user must match. + * + * @param user + * @param oldPassword current password. + * @param newPassword new password. + * @throws UserNotFoundException If the given user does not exist. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public void setPassword(User<T> user, final String oldPassword, final String newPassword) + throws UserNotFoundException, TransientException, AccessControlException + { + try + { + DN userDN = getUserDN(user); + DN subjectDN = getSubjectDN(); + if (!userDN.equals(subjectDN)) + { + throw new AccessControlException("Given user and authenticating user do not match"); + } + + ProxiedAuthorizationV2RequestControl control = + new ProxiedAuthorizationV2RequestControl("dn:" + getSubjectDN().toNormalizedString()); + Control[] controls = new Control[] {control}; + + PasswordModifyExtendedRequest passwordModifyRequest = + new PasswordModifyExtendedRequest(userDN.toNormalizedString(), oldPassword, newPassword, controls); + + PasswordModifyExtendedResult passwordModifyResult = (PasswordModifyExtendedResult) + getConnection().processExtendedOperation(passwordModifyRequest); + LdapDAO.checkLdapResult(passwordModifyResult.getResultCode()); + } + catch (LDAPException e) + { + logger.debug("setPassword Exception: " + e); + LdapDAO.checkLdapResult(e.getResultCode()); + } } /** @@ -595,7 +750,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public boolean isMember(T userID, String groupID) + public boolean isMember(final T userID, final String groupID) throws UserNotFoundException, TransientException, AccessControlException { @@ -767,7 +922,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO throw new IllegalArgumentException(userID + " not a valid user ID"); } - void addAttribute(List<Attribute> attributes, final String name, final String value) + private void addAttribute(List<Attribute> attributes, final String name, final String value) { if (value != null && !value.isEmpty()) { @@ -775,6 +930,18 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO } } + private void addModification(List<Modification> mods, final String name, final String value) + { + if (value != null && !value.isEmpty()) + { + mods.add(new Modification(ModificationType.REPLACE, name, value)); + } + else + { + mods.add(new Modification(ModificationType.REPLACE, name)); + } + } + /** * Checks the Ldap result code, and if the result is not SUCCESS, * throws an appropriate exception. This is the place to decide on 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/ACSearchRunner.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/ACSearchRunner.java similarity index 99% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/ACSearchRunner.java index df069f8bc4d5ca996d888616604e2198d4d4abed..a6409ad49a03dfa8167385d66256577d3ae235f3 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/ACSearchRunner.java @@ -66,31 +66,15 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; - -import java.io.IOException; -import java.security.AccessControlContext; -import java.security.AccessControlException; -import java.security.AccessController; -import java.security.Principal; -import java.util.Collection; -import java.util.Date; -import java.util.Iterator; -import java.util.Set; - -import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; -import javax.servlet.http.HttpServletResponse; - -import org.apache.log4j.Logger; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupNotFoundException; -import ca.nrc.cadc.ac.xml.GroupsWriter; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.ac.server.GroupPersistence; import ca.nrc.cadc.ac.server.PluginFactory; import ca.nrc.cadc.ac.server.RequestValidator; +import ca.nrc.cadc.ac.xml.GroupsWriter; import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; @@ -100,9 +84,23 @@ import ca.nrc.cadc.uws.server.JobRunner; import ca.nrc.cadc.uws.server.JobUpdater; import ca.nrc.cadc.uws.server.SyncOutput; import ca.nrc.cadc.uws.util.JobLogInfo; +import org.apache.log4j.Logger; + +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.security.AccessControlContext; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.Principal; import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.Set; public class ACSearchRunner implements JobRunner { diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/AddGroupMemberAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AddGroupMemberAction.java similarity index 99% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/AddGroupMemberAction.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AddGroupMemberAction.java index c842e9708c09ea603ebc77c21173802586bd1bea..61669fa27d74b9f372b10fe30c4225c1e63d6a6b 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/AddGroupMemberAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AddGroupMemberAction.java @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupAlreadyExistsException; diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/AddUserMemberAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberAction.java similarity index 98% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/AddUserMemberAction.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberAction.java index 7c6873401e1aa28c94b36e0980ec70bedf72bea5..cdf6093abea691a7412e1fd0a4a6bacd36c12cd4 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/AddUserMemberAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberAction.java @@ -66,18 +66,16 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.MemberAlreadyExistsException; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.server.GroupPersistence; -import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.auth.AuthenticationUtil; import java.security.Principal; import java.util.ArrayList; import java.util.List; -import java.util.Set; public class AddUserMemberAction extends GroupsAction { diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/CreateGroupAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/CreateGroupAction.java similarity index 99% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/CreateGroupAction.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/CreateGroupAction.java index 47cdc9bc198a5bdc0e01c0e93aa501cb9bffc0bb..f282d722627e25796756e8921ae77ca2fb4f3940 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/CreateGroupAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/CreateGroupAction.java @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import java.io.InputStream; import java.util.ArrayList; diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/DeleteGroupAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupAction.java similarity index 99% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/DeleteGroupAction.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupAction.java index 8f619fa381cc12469cf9ff0b196c280364d22571..2c96f279f30a5108de5be505761094a2c4e5bf9a 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/DeleteGroupAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupAction.java @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import java.util.ArrayList; diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GetGroupAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GetGroupAction.java similarity index 99% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GetGroupAction.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GetGroupAction.java index 97a2b52ea289c730ff74ae3637cfb16a0e6b205d..3d7d9646f6692d46f3c76e2943702a7d55707bb2 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GetGroupAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GetGroupAction.java @@ -65,7 +65,7 @@ * $Revision: 4 $ * ************************************************************************ - */package ca.nrc.cadc.ac.server.web; + */package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.server.GroupPersistence; diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GetGroupNamesAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GetGroupNamesAction.java similarity index 99% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GetGroupNamesAction.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GetGroupNamesAction.java index a29e5fcf29a37ebf66ded5fd96cff4edbe77f26c..a62ef9526d1ff961f6f9b0a88ea82283762f061c 100644 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GetGroupNamesAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GetGroupNamesAction.java @@ -67,7 +67,7 @@ ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import java.io.Writer; import java.util.Collection; diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupLogInfo.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupLogInfo.java similarity index 99% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupLogInfo.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupLogInfo.java index 512610114aa61aa3cc24d30a2fd62c3922f93e7c..38739a0849e2755fdcd6c42503a9e402a3cae8dd 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupLogInfo.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupLogInfo.java @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.log.ServletLogInfo; import java.util.List; diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupsAction.java similarity index 99% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsAction.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupsAction.java index 42c0ac3cf8138d192991ae40b80da515016fd1dc..4ef1811573d47b135823e0e584ae9b2ace14b720 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupsAction.java @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import java.io.IOException; import java.security.AccessControlException; diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsActionFactory.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupsActionFactory.java similarity index 99% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsActionFactory.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupsActionFactory.java index 9263dde60b2cb5f343596eae7a6c41064ffe08a4..c2aaf942be82e190f33b7f9e1f7cb40aa6fafe97 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsActionFactory.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupsActionFactory.java @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import java.io.IOException; import java.net.URL; diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsServlet.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupsServlet.java similarity index 99% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsServlet.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupsServlet.java index dd62ed5cdb871629bb86aa975b1a24e7b583e492..cd4682325e14892bdb73c8cd96c7ed1782368730 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupsServlet.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/GroupsServlet.java @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import java.io.IOException; diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyGroupAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/ModifyGroupAction.java similarity index 99% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyGroupAction.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/ModifyGroupAction.java index 425951d7c80820977ec32eaef9f7af85d2a967d9..444e335dc3594ec7543872a5f77db25ef0cc4c32 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyGroupAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/ModifyGroupAction.java @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import java.io.InputStream; import java.util.ArrayList; diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/RemoveGroupMemberAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/RemoveGroupMemberAction.java similarity index 98% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/RemoveGroupMemberAction.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/RemoveGroupMemberAction.java index 269984b17e2d626ed58551a7c5ad130349405cc4..a05d17f93d73a061e96bb44975b3f68548b3b7c5 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/RemoveGroupMemberAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/RemoveGroupMemberAction.java @@ -66,14 +66,13 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupNotFoundException; import ca.nrc.cadc.ac.server.GroupPersistence; import java.util.ArrayList; import java.util.List; -import java.util.Set; public class RemoveGroupMemberAction extends GroupsAction { diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/RemoveUserMemberAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberAction.java similarity index 98% rename from projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/RemoveUserMemberAction.java rename to projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberAction.java index 9b4d34f73c8af063650ac3ecf5245ba2c7058b5b..20dcf8b4a32af6119d4033ea5b72db0389218ba1 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/RemoveUserMemberAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberAction.java @@ -66,13 +66,12 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.MemberNotFoundException; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.server.GroupPersistence; -import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.auth.AuthenticationUtil; import java.security.Principal; import java.util.ArrayList; 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..df6880b92f0ab5c5bf2116e956b3d88bfc7c5798 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 @@ -68,6 +68,17 @@ */ package ca.nrc.cadc.ac.server.web.users; +import ca.nrc.cadc.ac.PersonalDetails; +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserNotFoundException; +import ca.nrc.cadc.ac.UserRequest; +import ca.nrc.cadc.ac.server.PluginFactory; +import ca.nrc.cadc.ac.server.UserPersistence; +import ca.nrc.cadc.net.TransientException; +import org.apache.log4j.Logger; + +import javax.security.auth.Subject; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.io.Writer; @@ -77,18 +88,6 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Map; -import javax.security.auth.Subject; -import javax.servlet.http.HttpServletResponse; - -import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.ac.UserRequest; -import org.apache.log4j.Logger; - -import ca.nrc.cadc.ac.UserNotFoundException; -import ca.nrc.cadc.ac.server.PluginFactory; -import ca.nrc.cadc.ac.server.UserPersistence; -import ca.nrc.cadc.net.TransientException; - public abstract class UsersAction implements PrivilegedExceptionAction<Object> { @@ -278,7 +277,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/src/ca/nrc/cadc/ac/server/web/users/UsersServlet.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersServlet.java index 926ce997fb15e7cd01df865088749b3f82c429e1..c3f2e53c75821f6de8d170d5d1a02393196ca316 100644 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersServlet.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersServlet.java @@ -173,13 +173,14 @@ public class UsersServlet extends HttpServlet { final String requestedContentType = request.getHeader("Accept"); - if (!UsersAction.JSON_CONTENT_TYPE.equals(requestedContentType)) + if (StringUtil.hasText(requestedContentType) + && requestedContentType.contains(UsersAction.JSON_CONTENT_TYPE)) { - return UsersAction.DEFAULT_CONTENT_TYPE; + return UsersAction.JSON_CONTENT_TYPE; } else { - return requestedContentType; + return UsersAction.DEFAULT_CONTENT_TYPE; } } } diff --git a/projects/cadcAccessControl-Server/test/LdapConfig.test.properties b/projects/cadcAccessControl-Server/test/LdapConfig.test.properties index 2354a157763992f801c862d5d1945663edd9b055..99ee0cc862a105684c6bd2cad55cba5c8ed42640 100644 --- a/projects/cadcAccessControl-Server/test/LdapConfig.test.properties +++ b/projects/cadcAccessControl-Server/test/LdapConfig.test.properties @@ -1,9 +1,13 @@ # 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 = 636 -proxyUser = webproxy -usersDn = ou=Users,ou=ds,dc=canfar,dc=net +port = 389 +proxyUser = testproxy +usersDn = ou=Users,ou=ds,dc=testcanfar userRequestsDN = ou=UserRequests,ou=ds,dc=testcanfar -newUsersDn = ou=NewUsers,ou=ds,dc=canfar,dc=net -groupsDn = ou=Groups,ou=ds,dc=canfar,dc=net -adminGroupsDn = ou=adminGroups,ou=ds,dc=canfar,dc=net \ No newline at end of file +groupsDn = ou=Groups,ou=ds,dc=testcanfar +adminGroupsDn = ou=adminGroups,ou=ds,dc=testcanfar \ No newline at end of file diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/RequestValidatorTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/RequestValidatorTest.java index 94760917ca297b709b57a06d0700769e95dd9d05..e54ea3da63d1689021d071ae82a86d58c12952f6 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/RequestValidatorTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/RequestValidatorTest.java @@ -69,11 +69,11 @@ package ca.nrc.cadc.ac.server; import ca.nrc.cadc.ac.Role; -import ca.nrc.cadc.ac.server.web.AddUserMemberActionTest; +import ca.nrc.cadc.ac.server.web.groups.AddUserMemberActionTest; import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.util.Log4jInit; import ca.nrc.cadc.uws.Parameter; -import java.security.Principal; + import java.util.ArrayList; import java.util.List; import org.apache.log4j.Level; diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java index bad3d32ac6ec804357f8bae67f88707fdca8d619..2f9bcdf27a8fb962fd5d1645f997975200956706 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java @@ -67,23 +67,6 @@ package ca.nrc.cadc.ac.server.ldap; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.security.AccessControlException; -import java.security.PrivilegedExceptionAction; -import java.util.Collection; - -import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; - -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.junit.BeforeClass; -import org.junit.Test; - import ca.nrc.cadc.ac.ActivatedGroup; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupAlreadyExistsException; @@ -91,8 +74,23 @@ import ca.nrc.cadc.ac.GroupNotFoundException; import ca.nrc.cadc.ac.GroupProperty; import ca.nrc.cadc.ac.Role; import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.util.Log4jInit; import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.util.Log4jInit; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; +import java.security.AccessControlException; +import java.security.PrivilegedExceptionAction; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class LdapGroupDAOTest extends AbstractLdapDAOTest { 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 aa47a3091287bdbdb006f9876b389df026ce05d6..0e592c8012b889cd4b425b5bae0b3089a647f1f4 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 @@ -86,9 +86,13 @@ import java.security.Principal; import java.security.PrivilegedExceptionAction; import java.util.Collection; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -public class LdapUserDAOTest extends AbstractLdapDAOTest +public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest { private static final Logger log = Logger.getLogger(LdapUserDAOTest.class); @@ -97,10 +101,10 @@ public class LdapUserDAOTest 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); @@ -118,12 +122,12 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { return new LdapUserDAO(config); } - + String getUserID() { return "CadcDaoTestUser-" + System.currentTimeMillis(); } - + /** * Test of addUser method, of class LdapUserDAO. */ @@ -143,7 +147,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest User<HttpPrincipal> actual = getUserDAO().addUser(userRequest); check(expected, actual); } - + /** * Test of getUser method, of class LdapUserDAO. */ @@ -156,13 +160,14 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest // do everything as owner Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { - public Object run() throws Exception + public Object run() + throws Exception { try { User<X500Principal> actual = getUserDAO().getUser(testUser.getUserID()); check(testUser, actual); - + return null; } catch (Exception e) @@ -189,19 +194,24 @@ public class LdapUserDAOTest 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) @@ -211,7 +221,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } }); } - + /** * Test of getUserGroups method, of class LdapUserDAO. */ @@ -227,14 +237,15 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest public Object run() throws Exception { try - { + { boolean isMember = getUserDAO().isMember(testUser.getUserID(), "foo"); - assertFalse(isMember); - - String groupDN = "cn=cadcdaotestgroup1," + config.getGroupsDN(); - isMember = getUserDAO().isMember(testUser.getUserID(), groupDN); - assertTrue(isMember); - + assertFalse("Membership should not exist.", isMember); + + String groupDN = "cn=cadcdaotestgroup1," + config.getGroupsDN(); + isMember = getUserDAO().isMember(testUser.getUserID(), + groupDN); + assertTrue("Membership should exist.", isMember); + return null; } catch (Exception e) @@ -244,7 +255,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } }); } - + /** * Test of getMember. */ @@ -260,7 +271,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest public Object run() throws Exception { try - { + { User<X500Principal> actual = getUserDAO().getMember(new DN(testUserDN)); check(testUser, actual); return null; @@ -271,7 +282,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } } }); - + // should also work as a different user subject = new Subject(); subject.getPrincipals().add(new HttpPrincipal("CadcDaoTest2")); @@ -279,10 +290,11 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest // do everything as owner Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { - public Object run() throws Exception + public Object run() + throws Exception { try - { + { User<X500Principal> actual = getUserDAO().getMember(new DN(testUserDN)); check(testUser, actual); return null; @@ -290,11 +302,11 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest catch (Exception e) { throw new Exception("Problems", e); - } + } } }); } - + /** * Test of testGetCadcUserIDs. */ @@ -302,36 +314,37 @@ public class LdapUserDAOTest 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; @@ -343,27 +356,238 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } }); assertEquals("User listing should be independent of the access type", - users1, users2); + users1, users2); } - + +// @Test + public void testSetPassword() throws Exception + { +// LDAPConnection connection = +// new LDAPConnection(SocketFactory.getDefault(), config.getServer(), config.getPort()); +// connection.bind(config.getAdminUserDN(), config.getAdminPasswd()); +// +// // Create an SSLUtil instance that is configured to trust any certificate. +// SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager()); +// SSLContext sslContext = sslUtil.createSSLContext(); +// StartTLSExtendedRequest startTLSRequest = new StartTLSExtendedRequest(sslContext); +// ExtendedResult startTLSResult = connection.processExtendedOperation(startTLSRequest); +// LDAPTestUtils.assertResultCodeEquals(startTLSResult, ResultCode.SUCCESS); + + // Create a test user with a known password + final User<HttpPrincipal> testUser2; + final String username = getUserID(); + final String password = "foo"; + final String newPassword = "bar"; + + HttpPrincipal principal = new HttpPrincipal(username); + testUser2 = new User<HttpPrincipal>(principal); + testUser2.getIdentities().add(principal); + testUser2.details.add(new PersonalDetails("firstName", "lastName")); + final UserRequest userRequest = new UserRequest(testUser2, password); + + // add the user + Subject subject = new Subject(); + subject.getPrincipals().add(testUser2.getUserID()); + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() + throws Exception + { + try + { + return getUserDAO().newUser(userRequest); + } + catch (Exception e) + { + fail("exception updating user: " + e.getMessage()); + } + return null; + } + }); + + // authenticate new username and password + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() + throws Exception + { + try + { + getUserDAO().loginUser(username, password); + } + catch (Exception e) + { + fail("exception during login: " + e.getMessage()); + } + return null; + } + }); + + // anonymous access should throw exception + subject = new Subject(); + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + getUserDAO().setPassword(testUser2, password, newPassword); + fail("should throw exception if subject and user are not the same"); + } + catch (Exception ignore){} + return null; + } + }); + + // change the password + subject.getPrincipals().add(testUser2.getUserID()); + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() + throws Exception + { + try + { + getUserDAO().setPassword(testUser2, password, newPassword); + } + catch (Exception e) + { + e.printStackTrace(); + fail("exception setting password: " + e.getMessage()); + } + return null; + } + }); + + // verify new password + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() + throws Exception + { + try + { + getUserDAO().loginUser(username, password); + } + catch (Exception e) + { + fail("exception during login: " + e.getMessage()); + } + return null; + } + }); + + } + + @Test + public void testUpdateUser() throws Exception + { + // Create a test user + final User<HttpPrincipal> testUser2; + final String username = getUserID(); + final String password = "foo"; + + HttpPrincipal principal = new HttpPrincipal(username); + testUser2 = new User<HttpPrincipal>(principal); + testUser2.getIdentities().add(principal); + testUser2.details.add(new PersonalDetails("firstName", "lastName")); + final UserRequest userRequest = new UserRequest(testUser2, password); + + // add the user + Subject subject = new Subject(); + subject.getPrincipals().add(testUser2.getUserID()); + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() + throws Exception + { + try + { + return getUserDAO().newUser(userRequest); + } + catch (Exception e) + { + fail("exception updating user: " + e.getMessage()); + } + return null; + } + }); + + // update the user + for (UserDetails details : testUser2.details) + { + if (details instanceof PersonalDetails) + { + PersonalDetails pd = (PersonalDetails) details; + pd.email = "email2"; + pd.address = "address2"; + pd.institute = "institute2"; + pd.city = "city2"; + pd.country = "country2"; + } + } + + // anonymous access should throw exception + subject = new Subject(); + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() + throws Exception + { + try + { + getUserDAO().modifyUser(testUser2); + fail("should throw exception if subject and user are not the same"); + } + catch (Exception ignore) + { + } + return null; + } + }); + + // update the user + subject.getPrincipals().add(testUser2.getUserID()); + User<? extends Principal> updatedUser = + (User<? extends Principal>) Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() + throws Exception + { + try + { + return getUserDAO().modifyUser(testUser2); + } + catch (Exception e) + { + e.printStackTrace(); + fail("exception updating user: " + e.getMessage()); + } + return null; + } + }); + assertNotNull(updatedUser); + check(testUser2, updatedUser); + } + 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); @@ -376,7 +600,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } } } - + } - + } diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/AddGroupMemberActionTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddGroupMemberActionTest.java similarity index 99% rename from projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/AddGroupMemberActionTest.java rename to projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddGroupMemberActionTest.java index eb092c7f48d4e86880a3f9b2eafb2e840ecec592..8550e9ba2dfa13797a5da1a34c5a93fcd8261c10 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/AddGroupMemberActionTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddGroupMemberActionTest.java @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupAlreadyExistsException; diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/AddUserMemberActionTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberActionTest.java similarity index 98% rename from projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/AddUserMemberActionTest.java rename to projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberActionTest.java index 6488fd768583dd7d06841a16547158a6c8b32b6a..1cdb6f4fc1cf397c8388bbb7322fd39cbb845e61 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/AddUserMemberActionTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberActionTest.java @@ -66,10 +66,9 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.Group; -import ca.nrc.cadc.ac.GroupAlreadyExistsException; import ca.nrc.cadc.ac.MemberAlreadyExistsException; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.server.GroupPersistence; @@ -77,7 +76,7 @@ import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.util.Log4jInit; import java.security.Principal; -import javax.security.auth.x500.X500Principal; + import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.easymock.EasyMock; diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/DeleteGroupActionTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupActionTest.java similarity index 95% rename from projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/DeleteGroupActionTest.java rename to projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupActionTest.java index 4562671a6951e209e759a96993499782ede5a9e8..0994610208aab34a25f8b521508c6146283df352 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/DeleteGroupActionTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupActionTest.java @@ -66,22 +66,15 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.Group; -import ca.nrc.cadc.ac.MemberAlreadyExistsException; -import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.server.GroupPersistence; -import ca.nrc.cadc.ac.server.UserPersistence; -import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.util.Log4jInit; import java.security.Principal; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.easymock.EasyMock; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GetGroupNamesActionTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/GetGroupNamesActionTest.java similarity index 99% rename from projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GetGroupNamesActionTest.java rename to projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/GetGroupNamesActionTest.java index 0cb59383950ce877c3c5c88a4ee1da506adecce7..1f2d4d67b0f71e4a2734230b8308f04cd27d5353 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GetGroupNamesActionTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/GetGroupNamesActionTest.java @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.server.GroupPersistence; import ca.nrc.cadc.util.Log4jInit; diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GroupActionFactoryTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/GroupActionFactoryTest.java similarity index 99% rename from projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GroupActionFactoryTest.java rename to projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/GroupActionFactoryTest.java index f62d030cc6b0f9131a9681250664fbee8a97444c..3a9b19ccb053c960256ea8c67cd32fe39dac6544 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GroupActionFactoryTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/GroupActionFactoryTest.java @@ -65,7 +65,7 @@ ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import javax.servlet.http.HttpServletRequest; @@ -77,8 +77,6 @@ import org.junit.Test; import ca.nrc.cadc.util.Log4jInit; -import java.net.URL; - public class GroupActionFactoryTest { private final static Logger log = Logger.getLogger(GroupActionFactoryTest.class); diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GroupsActionTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/GroupsActionTest.java similarity index 98% rename from projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GroupsActionTest.java rename to projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/GroupsActionTest.java index 08b28e9725675f4d955688e194198862144b9f42..def8852585eaf9d5102a31ede3712bb7214504f0 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/GroupsActionTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/GroupsActionTest.java @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.GroupAlreadyExistsException; import ca.nrc.cadc.ac.GroupNotFoundException; @@ -76,18 +76,14 @@ import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.util.Log4jInit; -import java.io.ByteArrayOutputStream; -import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.security.AccessControlException; -import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.easymock.EasyMock; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.*; diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/RemoveGroupMemberActionTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveGroupMemberActionTest.java similarity index 97% rename from projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/RemoveGroupMemberActionTest.java rename to projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveGroupMemberActionTest.java index 7ccc5abb9753fd6ad5f1336e1ddfd4b46d8c1638..749d0076eed5527337e293ac48f4b11951d54a55 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/RemoveGroupMemberActionTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveGroupMemberActionTest.java @@ -66,10 +66,9 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.Group; -import ca.nrc.cadc.ac.GroupAlreadyExistsException; import ca.nrc.cadc.ac.GroupNotFoundException; import ca.nrc.cadc.ac.server.GroupPersistence; import ca.nrc.cadc.util.Log4jInit; @@ -77,9 +76,6 @@ import java.security.Principal; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.easymock.EasyMock; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/RemoveUserMemberActionTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberActionTest.java similarity index 98% rename from projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/RemoveUserMemberActionTest.java rename to projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberActionTest.java index fea4de56d5d4ff31e3f08e473eeb5d8f8111fc12..05609091e46dba3e1b60d8c307622578d75b62b3 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/RemoveUserMemberActionTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberActionTest.java @@ -66,10 +66,9 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.groups; import ca.nrc.cadc.ac.Group; -import ca.nrc.cadc.ac.MemberAlreadyExistsException; import ca.nrc.cadc.ac.MemberNotFoundException; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.server.GroupPersistence; @@ -80,9 +79,6 @@ import java.security.Principal; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.easymock.EasyMock; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; 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()); + } +}