From 0d5731ac52e35f6bc0888dc8ccbb1ea7c3bf6317 Mon Sep 17 00:00:00 2001 From: Jeff Burke <Jeff.Burke@nrc-cnrc.gc.ca> Date: Mon, 22 Jun 2015 10:21:00 -0700 Subject: [PATCH] s1734: added create user, updated get user --- projects/cadcAccessControl-Server/build.xml | 26 +- .../nrc/cadc/ac/server/UserPersistence.java | 51 +++ .../ca/nrc/cadc/ac/server/ldap/LdapDAO.java | 24 +- .../nrc/cadc/ac/server/ldap/LdapUserDAO.java | 350 ++++++++++++++---- .../ac/server/ldap/LdapUserPersistence.java | 107 ++++++ .../ac/server/web/users/CreateUserAction.java | 100 +++++ .../ac/server/web/users/DeleteUserAction.java | 94 +++++ .../ac/server/web/users/GetUserAction.java | 95 +++++ .../server/web/users/GetUserNamesAction.java | 20 +- .../ac/server/web/users/ModifyUserAction.java | 107 ++++++ .../cadc/ac/server/web/users/UserLogInfo.java | 12 +- .../cadc/ac/server/web/users/UsersAction.java | 56 +-- .../server/web/users/UsersActionFactory.java | 87 ++--- .../ac/server/web/users/UsersServlet.java | 10 +- .../cadc/ac/server/ldap/LdapUserDAOTest.java | 49 ++- .../web/users/UserActionFactoryTest.java | 268 ++++++++++++++ .../ac/server/web/users/UsersActionTest.java | 220 +++++++++++ 17 files changed, 1450 insertions(+), 226 deletions(-) create mode 100644 projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java create mode 100644 projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/DeleteUserAction.java create mode 100644 projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java create mode 100644 projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java mode change 100755 => 100644 projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserLogInfo.java mode change 100755 => 100644 projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersAction.java mode change 100755 => 100644 projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersActionFactory.java mode change 100755 => 100644 projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersServlet.java create mode 100644 projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java create mode 100644 projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UsersActionTest.java diff --git a/projects/cadcAccessControl-Server/build.xml b/projects/cadcAccessControl-Server/build.xml index f30a6185..14616e31 100644 --- a/projects/cadcAccessControl-Server/build.xml +++ b/projects/cadcAccessControl-Server/build.xml @@ -132,17 +132,19 @@ </copy> </target> - <!--<target name="test" depends="compile,compile-test,resources">--> - <!--<echo message="Running test suite..." />--> - <!--<junit printsummary="yes" haltonfailure="yes" fork="yes">--> - <!--<classpath>--> - <!--<pathelement path="${build}/class"/>--> - <!--<pathelement path="${build}/test/class"/>--> - <!--<pathelement path="${testingJars}"/>--> - <!--</classpath>--> - <!--<test name="ca.nrc.cadc.ac.server.ldap.LdapGroupDAOTest" />--> - <!--<formatter type="plain" usefile="false" />--> - <!--</junit>--> - <!--</target>--> + <target name="test" depends="compile,compile-test,resources"> + <echo message="Running test suite..." /> + <junit printsummary="yes" haltonfailure="yes" fork="yes"> + <classpath> + <pathelement path="${build}/class"/> + <pathelement path="${build}/test/class"/> + <pathelement path="${testingJars}"/> + </classpath> + <test name="ca.nrc.cadc.ac.server.ldap.LdapUserDAOTest" /> + <!--<test name="ca.nrc.cadc.ac.server.web.users.UserActionFactoryTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.users.UsersActionTest" />--> + <formatter type="plain" usefile="false" /> + </junit> + </target> </project> 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 703a3d62..4ca163f9 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 @@ -78,6 +78,29 @@ import java.util.Collection; public abstract interface UserPersistence<T extends Principal> { + /** + * Get all user names. + * + * @return A collection of strings. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public Collection<String> getUserNames() + throws TransientException, AccessControlException; + + /** + * Add the new user. + * + * @param user + * + * @return User instance. + * + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public abstract User<T> addUser(User<T> user) + throws TransientException, AccessControlException; + /** * Get the user specified by userID. * @@ -93,6 +116,34 @@ public abstract interface UserPersistence<T extends Principal> throws UserNotFoundException, TransientException, AccessControlException; + /** + * Updated the user specified by User. + * + * @param user + * + * @return User instance. + * + * @throws UserNotFoundException when the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public abstract User<T> modifyUser(User<T> user) + throws UserNotFoundException, TransientException, + AccessControlException; + + /** + * Delete the user specified by userID. + * + * @param userID The userID. + * + * @throws UserNotFoundException when the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public abstract void deleteUser(T userID) + throws UserNotFoundException, TransientException, + AccessControlException; + /** * Get all groups the user specified by userID belongs to. * 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 9c3b3c87..90005ee0 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,21 +68,27 @@ */ package ca.nrc.cadc.ac.server.ldap; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.auth.NumericPrincipal; +import ca.nrc.cadc.auth.OpenIdPrincipal; +import ca.nrc.cadc.net.TransientException; +import com.unboundid.ldap.sdk.DN; +import com.unboundid.ldap.sdk.LDAPConnection; +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 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; -import java.security.*; -import java.util.Set; - -import com.unboundid.ldap.sdk.*; - -import ca.nrc.cadc.auth.*; -import ca.nrc.cadc.net.TransientException; - public abstract class 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 469ffd7b..e9b7580a 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 @@ -81,11 +81,15 @@ import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl; import org.apache.log4j.Logger; import ca.nrc.cadc.ac.PersonalDetails; +import ca.nrc.cadc.ac.PosixDetails; import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserDetails; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; +import java.util.ArrayList; +import java.util.List; public class LdapUserDAO<T extends Principal> extends LdapDAO @@ -93,21 +97,46 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO private static final Logger logger = Logger.getLogger(LdapUserDAO.class); // Map of identity type to LDAP attribute - private Map<Class<?>, String> userLdapAttrib = - new HashMap<Class<?>, String>(); - - // User attributes returned to the GMS - private static final String LDAP_FNAME = "givenname"; - private static final String LDAP_LNAME = "sn"; - //TODO to add the rest - private String[] userAttribs = new String[]{LDAP_FNAME, LDAP_LNAME}; - private String[] memberAttribs = new String[]{LDAP_FNAME, LDAP_LNAME}; + private final Map<Class<?>, String> userLdapAttrib = new HashMap<Class<?>, String>(); + + // Returned User attributes + protected static final String LDAP_OBJECT_CLASS = "objectClass"; + 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"; + protected static final String LDAP_COMMON_NAME = "cn"; + protected static final String LDAP_DISTINGUISHED_NAME = "distinguishedName"; + protected static final String LDAP_FIRST_NAME = "givenName"; + protected static final String LDAP_LAST_NAME = "sn"; + protected static final String LDAP_ADDRESS = "address"; + protected static final String LDAP_CITY = "city"; + protected static final String LDAP_COUNTRY = "country"; + 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 + }; + private String[] memberAttribs = new String[] + { + LDAP_FIRST_NAME, LDAP_LAST_NAME + }; public LdapUserDAO(LdapConfig config) { super(config); - this.userLdapAttrib.put(HttpPrincipal.class, "uid"); - this.userLdapAttrib.put(X500Principal.class, "distinguishedname"); + this.userLdapAttrib.put(HttpPrincipal.class, LDAP_UID); + this.userLdapAttrib.put(X500Principal.class, LDAP_DISTINGUISHED_NAME); // add the id attributes to user and member attributes String[] princs = userLdapAttrib.values() @@ -126,6 +155,87 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO } + /** + * Add the specified user.. + * + * @param user The user to add. + * @return User instance. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public User<T> addUser(final User<T> user) + throws TransientException + { + final Class userType = user.getUserID().getClass(); + String searchField = userLdapAttrib.get(userType); + if (searchField == null) + { + throw new IllegalArgumentException( + "Unsupported principal type " + userType); + } + + try + { + // add new user + DN userDN = getUserDN(user.getUserID().getName()); + List<Attribute> attributes = new ArrayList<Attribute>(); + addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_CADC_ACCOUNT); + addAttribute(attributes, LDAP_COMMON_NAME, user.getUserID().getName()); + addAttribute(attributes, LDAP_DISTINGUISHED_NAME, userDN.toNormalizedString()); + + for (UserDetails details : user.details) + { + if (details.getClass() == PersonalDetails.class) + { + PersonalDetails pd = (PersonalDetails) details; + 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); + addAttribute(attributes, LDAP_COUNTRY, pd.country); + addAttribute(attributes, LDAP_EMAIL, pd.email); + addAttribute(attributes, LDAP_INSTITUTE, pd.institute); + } + 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); + } + } + + AddRequest addRequest = new AddRequest(userDN, attributes); + addRequest.addControl( + new ProxiedAuthorizationV2RequestControl( + "dn:" + getSubjectDN().toNormalizedString())); + + LDAPResult result = getConnection().add(addRequest); + LdapDAO.checkLdapResult(result.getResultCode()); + + getConnection().reconnect(); + try + { + return getUser(user.getUserID()); + } + catch (UserNotFoundException e) + { + throw new RuntimeException("BUG: new user not found"); + } + } + catch (LDAPException e) + { + System.out.println("LDAPe: " + e); + System.out.println("LDAPrc: " + e.getResultCode()); + logger.debug("addUser Exception: " + e, e); +// LdapDAO.checkLdapResult(e.getResultCode()); + throw new RuntimeException("Unexpected LDAP exception", e); + } + } + /** * Get the user specified by userID. * @@ -135,9 +245,8 @@ 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> getUser(T userID) - throws UserNotFoundException, TransientException, - AccessControlException + public User<T> getUser(final T userID) + throws UserNotFoundException, TransientException, AccessControlException { String searchField = userLdapAttrib.get(userID.getClass()); if (searchField == null) @@ -146,22 +255,19 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO "Unsupported principal type " + userID.getClass()); } - searchField = - "(&(objectclass=cadcaccount)(" + searchField + "=" + userID - .getName() + "))"; + searchField = "(&(objectclass=cadcaccount)(" + + searchField + "=" + userID.getName() + "))"; SearchResultEntry searchResult = null; try { - SearchRequest searchRequest = new SearchRequest(config.getUsersDN(), - SearchScope.SUB, - searchField, - userAttribs); + SearchRequest searchRequest = + new SearchRequest(config.getUsersDN(), SearchScope.SUB, + searchField, userAttribs); searchRequest.addControl( - new ProxiedAuthorizationV2RequestControl("dn:" + - getSubjectDN() - .toNormalizedString())); + new ProxiedAuthorizationV2RequestControl( + "dn:" + getSubjectDN().toNormalizedString())); searchResult = getConnection().searchForEntry(searchRequest); } @@ -177,16 +283,118 @@ 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)))); - - String fname = searchResult.getAttributeValue(LDAP_FNAME); - String lname = searchResult.getAttributeValue(LDAP_LNAME); - user.details.add(new PersonalDetails(fname, lname)); - //TODO populate user with the other returned personal or posix attributes + 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); + PersonalDetails personaDetails = new PersonalDetails(fname, lname); + personaDetails.address = searchResult.getAttributeValue(LDAP_ADDRESS); + personaDetails.city = searchResult.getAttributeValue(LDAP_CITY); + personaDetails.country = searchResult.getAttributeValue(LDAP_COUNTRY); + personaDetails.email = searchResult.getAttributeValue(LDAP_EMAIL); + personaDetails.institute = searchResult.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; } + + /** + * Get all group names. + * + * @return A collection of strings + * + * @throws TransientException If an temporary, unexpected problem occurred. + */ + public Collection<String> getUserNames() + throws TransientException + { + try + { + Filter filter = Filter.createPresenceFilter(LDAP_COMMON_NAME); + String [] attributes = new String[] {LDAP_COMMON_NAME, LDAP_NSACCOUNTLOCK}; + + SearchRequest searchRequest = + new SearchRequest(config.getGroupsDN(), + SearchScope.SUB, filter, attributes); + + SearchResult searchResult = null; + try + { + searchResult = getConnection().search(searchRequest); + } + catch (LDAPSearchException e) + { + if (e.getResultCode() == ResultCode.NO_SUCH_OBJECT) + { + logger.debug("Could not find groups root", e); + throw new IllegalStateException("Could not find groups root"); + } + } + + LdapDAO.checkLdapResult(searchResult.getResultCode()); + List<String> groupNames = new ArrayList<String>(); + for (SearchResultEntry next : searchResult.getSearchEntries()) + { + if (!next.hasAttribute(LDAP_NSACCOUNTLOCK)) + { + groupNames.add(next.getAttributeValue(LDAP_COMMON_NAME)); + } + } + + return groupNames; + } + catch (LDAPException e1) + { + logger.debug("getGroupNames Exception: " + e1, e1); + LdapDAO.checkLdapResult(e1.getResultCode()); + throw new IllegalStateException("Unexpected exception: " + e1.getMatchedDN(), e1); + } + } + + /** + * Updated the user specified by User. + * + * @param user + * + * @return User instance. + * + * @throws UserNotFoundException when the user is not found. + * @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 + { + return null; + } + + /** + * Delete the user specified by userID. + * + * @param userID The userID. + * + * @throws UserNotFoundException when the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public void deleteUser(final T userID) + throws UserNotFoundException, TransientException, + AccessControlException + { + + } /** * Get all groups the user specified by userID belongs to. @@ -216,11 +424,11 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO Filter filter = Filter.createANDFilter( Filter.createEqualityFilter(searchField, user.getUserID().getName()), - Filter.createPresenceFilter("memberOf")); + Filter.createPresenceFilter(LDAP_MEMBEROF)); SearchRequest searchRequest = new SearchRequest(config.getUsersDN(), SearchScope.SUB, - filter, "memberOf"); + filter, LDAP_MEMBEROF); searchRequest.addControl( new ProxiedAuthorizationV2RequestControl("dn:" + @@ -242,7 +450,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO if (searchResult != null) { - String[] members = searchResult.getAttributeValues("memberOf"); + String[] members = searchResult.getAttributeValues(LDAP_MEMBEROF); if (members != null) { for (String member : members) @@ -290,11 +498,11 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO Filter filter = Filter.createANDFilter( Filter.createEqualityFilter(searchField, user.getUserID().getName()), - Filter.createEqualityFilter("memberOf", groupID)); + Filter.createEqualityFilter(LDAP_MEMBEROF, groupID)); SearchRequest searchRequest = new SearchRequest(config.getUsersDN(), SearchScope.SUB, - filter, "cn"); + filter, LDAP_COMMON_NAME); searchRequest.addControl( new ProxiedAuthorizationV2RequestControl("dn:" + @@ -313,41 +521,6 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO return false; } -// public boolean isMember(T userID, String groupID) -// throws UserNotFoundException, TransientException, -// AccessControlException -// { -// try -// { -// String searchField = (String) userLdapAttrib.get(userID.getClass()); -// if (searchField == null) -// { -// throw new IllegalArgumentException( -// "Unsupported principal type " + userID.getClass()); -// } -// -// User<T> user = getUser(userID); -// DN userDN = getUserDN(user); -// -// CompareRequest compareRequest = -// new CompareRequest(userDN.toNormalizedString(), -// "memberOf", groupID); -// -// compareRequest.addControl( -// new ProxiedAuthorizationV2RequestControl("dn:" + -// getSubjectDN().toNormalizedString())); -// -// CompareResult compareResult = -// getConnection().compare(compareRequest); -// return compareResult.compareMatched(); -// } -// catch (LDAPException e) -// { -// LdapDAO.checkLdapResult(e.getResultCode()); -// throw new RuntimeException("Unexpected LDAP exception", e); -// } -// } - /** * Returns a member user identified by the X500Principal only. The * returned object has the fields required by the GMS. @@ -363,7 +536,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO throws UserNotFoundException, LDAPException { Filter filter = - Filter.createEqualityFilter("entrydn", + Filter.createEqualityFilter(LDAP_ENTRYDN, userDN.toNormalizedString()); SearchRequest searchRequest = @@ -388,8 +561,8 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO { user.getIdentities().add(new HttpPrincipal(princ)); } - String fname = searchResult.getAttributeValue(LDAP_FNAME); - String lname = searchResult.getAttributeValue(LDAP_LNAME); + String fname = searchResult.getAttributeValue(LDAP_FIRST_NAME); + String lname = searchResult.getAttributeValue(LDAP_LAST_NAME); user.details.add(new PersonalDetails(fname, lname)); return user; } @@ -427,7 +600,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO { SearchRequest searchRequest = new SearchRequest(this.config.getUsersDN(), SearchScope.SUB, - searchField, "entrydn"); + searchField, LDAP_ENTRYDN); searchResult = @@ -445,7 +618,30 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO logger.debug(msg); throw new UserNotFoundException(msg); } - return searchResult.getAttributeValueAsDN("entrydn"); + return searchResult.getAttributeValueAsDN(LDAP_ENTRYDN); + } + + protected DN getUserDN(final String userID) + throws LDAPException, TransientException + { + try + { + return new DN(LDAP_COMMON_NAME + "=" + userID + "," + config.getUsersDN()); + } + catch (LDAPException e) + { + logger.debug("getUserDN Exception: " + e, e); + LdapDAO.checkLdapResult(e.getResultCode()); + } + throw new IllegalArgumentException(userID + " not a valid user ID"); + } + + void addAttribute(List<Attribute> attributes, final String name, final String value) + { + if (value != null && !value.isEmpty()) + { + attributes.add(new Attribute(name, value)); + } } } 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 8511d254..971b9890 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 @@ -95,6 +95,54 @@ public class LdapUserPersistence<T extends Principal> logger.error("test/config/LdapConfig.properties file required.", e); } } + + public Collection<String> getUserNames() + throws TransientException, AccessControlException + { + LdapUserDAO<T> userDAO = null; + try + { + userDAO = new LdapUserDAO<T>(config); + Collection<String> ret = userDAO.getUserNames(); + return ret; + } + finally + { + if (userDAO != null) + { + userDAO.close(); + } + } + } + + /** + * Add the new user. + * + * @param user + * + * @return User instance. + * + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public User<T> addUser(User<T> user) + throws TransientException, AccessControlException + { + LdapUserDAO<T> userDAO = null; + try + { + userDAO = new LdapUserDAO<T>(this.config); + User<T> ret = userDAO.addUser(user); + return ret; + } + finally + { + if (userDAO != null) + { + userDAO.close(); + } + } + } /** * Get the user specified by userID. @@ -125,6 +173,65 @@ public class LdapUserPersistence<T extends Principal> } } } + + /** + * Updated the user specified by User. + * + * @param user + * + * @return User instance. + * + * @throws UserNotFoundException when the user is not found. + * @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 + { + LdapUserDAO<T> userDAO = null; + try + { + userDAO = new LdapUserDAO<T>(this.config); + User<T> ret = userDAO.modifyUser(user); + return ret; + } + finally + { + if (userDAO != null) + { + userDAO.close(); + } + } + } + + /** + * Delete the user specified by userID. + * + * @param userID The userID. + * + * @throws UserNotFoundException when the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public void deleteUser(T userID) + throws UserNotFoundException, TransientException, + AccessControlException + { + LdapUserDAO<T> userDAO = null; + try + { + userDAO = new LdapUserDAO<T>(this.config); + userDAO.deleteUser(userID); + } + finally + { + if (userDAO != null) + { + userDAO.close(); + } + } + } /** * Get all groups the user specified by userID belongs to. diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java new file mode 100644 index 00000000..63d4f258 --- /dev/null +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java @@ -0,0 +1,100 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2014. (c) 2014. + * 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/>. + * + * $Revision: 4 $ + * + ************************************************************************ + */ +package ca.nrc.cadc.ac.server.web.users; + +import java.io.InputStream; +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserReader; +import ca.nrc.cadc.ac.UserWriter; +import ca.nrc.cadc.ac.server.UserPersistence; +import java.security.Principal; + +public class CreateUserAction extends UsersAction +{ + private final InputStream inputStream; + + CreateUserAction(UserLogInfo logInfo, InputStream inputStream) + { + super(logInfo); + this.inputStream = inputStream; + } + + public Object run() + throws Exception + { + UserPersistence userPersistence = getUserPersistence(); + User<? extends Principal> user = UserReader.read(this.inputStream); + User<? extends Principal> newUser = userPersistence.addUser(user); + this.response.setContentType("application/xml"); + UserWriter.write(newUser, this.response.getOutputStream()); + logUserInfo(newUser.getUserID().getName()); + return null; + } + +} diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/DeleteUserAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/DeleteUserAction.java new file mode 100644 index 00000000..806e8f98 --- /dev/null +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/DeleteUserAction.java @@ -0,0 +1,94 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2014. (c) 2014. + * 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/>. + * + * $Revision: 4 $ + * + ************************************************************************ + */ +package ca.nrc.cadc.ac.server.web.users; + +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.server.UserPersistence; +import java.security.Principal; + +public class DeleteUserAction extends UsersAction +{ + private final Principal userID; + + DeleteUserAction(UserLogInfo logInfo, Principal userID) + { + super(logInfo); + this.userID = userID; + } + + public Object run() + throws Exception + { + UserPersistence userPersistence = getUserPersistence(); + User<? extends Principal> deletedUser = userPersistence.getUser(userID); + userPersistence.deleteUser(deletedUser.getUserID()); + return null; + } + +} diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java new file mode 100644 index 00000000..3bf584cd --- /dev/null +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java @@ -0,0 +1,95 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2014. (c) 2014. + * 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/>. + * + * $Revision: 4 $ + * + ************************************************************************ + */package ca.nrc.cadc.ac.server.web.users; + +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserWriter; +import ca.nrc.cadc.ac.server.UserPersistence; +import java.security.Principal; + +public class GetUserAction extends UsersAction +{ + private final Principal userID; + + GetUserAction(UserLogInfo logInfo, Principal userID) + { + super(logInfo); + this.userID = userID; + } + + public Object run() + throws Exception + { + UserPersistence userPersistence = getUserPersistence(); + User<? extends Principal> user = userPersistence.getUser(userID); + this.response.setContentType("application/xml"); + UserWriter.write(user, this.response.getOutputStream()); + return null; + } + +} diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserNamesAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserNamesAction.java index a29e5fcf..bd2e7859 100644 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserNamesAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserNamesAction.java @@ -67,21 +67,21 @@ ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.users; import java.io.Writer; import java.util.Collection; import org.apache.log4j.Logger; -import ca.nrc.cadc.ac.server.GroupPersistence; +import ca.nrc.cadc.ac.server.UserPersistence; -public class GetGroupNamesAction extends GroupsAction +public class GetUserNamesAction extends UsersAction { - private static final Logger log = Logger.getLogger(GetGroupNamesAction.class); + private static final Logger log = Logger.getLogger(GetUserNamesAction.class); - GetGroupNamesAction(GroupLogInfo logInfo) + GetUserNamesAction(UserLogInfo logInfo) { super(logInfo); } @@ -89,20 +89,20 @@ public class GetGroupNamesAction extends GroupsAction public Object run() throws Exception { - GroupPersistence groupPersistence = getGroupPersistence(); - Collection<String> groups = groupPersistence.getGroupNames(); - log.debug("Found " + groups.size() + " group names"); + UserPersistence userPersistence = getUserPersistence(); + Collection<String> users = userPersistence.getUserNames(); + log.debug("Found " + users.size() + " user names"); response.setContentType("text/plain"); log.debug("Set content-type to text/plain"); Writer writer = response.getWriter(); boolean start = true; - for (final String group : groups) + for (final String user : users) { if (!start) { writer.write("\r\n"); } - writer.write(group); + writer.write(user); start = false; } diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java new file mode 100644 index 00000000..9f7cc815 --- /dev/null +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java @@ -0,0 +1,107 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2014. (c) 2014. + * 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/>. + * + * $Revision: 4 $ + * + ************************************************************************ + */ +package ca.nrc.cadc.ac.server.web.users; + +import java.io.InputStream; +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserReader; +import ca.nrc.cadc.ac.server.UserPersistence; +import java.security.Principal; + +public class ModifyUserAction extends UsersAction +{ + private final Principal userID; + private final String request; + private final InputStream inputStream; + + ModifyUserAction(UserLogInfo logInfo, Principal userID, + final String request, InputStream inputStream) + { + super(logInfo); + this.userID = userID; + this.request = request; + this.inputStream = inputStream; + } + + public Object run() + throws Exception + { + UserPersistence userPersistence = getUserPersistence(); + User<? extends Principal> user = UserReader.read(this.inputStream); + User<? extends Principal> oldUser = userPersistence.getUser(userID); + userPersistence.modifyUser(user); + + logUserInfo(user.getUserID().getName()); + + this.response.sendRedirect(request); + + return null; + } + +} diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserLogInfo.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserLogInfo.java old mode 100755 new mode 100644 index 51261011..79f4f138 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserLogInfo.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserLogInfo.java @@ -66,19 +66,17 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.users; + import ca.nrc.cadc.log.ServletLogInfo; -import java.util.List; import javax.servlet.http.HttpServletRequest; -public class GroupLogInfo extends ServletLogInfo +public class UserLogInfo extends ServletLogInfo { - public String groupID; - public List<String> addedMembers; - public List<String> deletedMembers; + public String userName; - public GroupLogInfo(HttpServletRequest request) + public UserLogInfo(HttpServletRequest request) { super(request); } 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 old mode 100755 new mode 100644 index 42c0ac3c..697357e9 --- 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 @@ -66,38 +66,32 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.users; import java.io.IOException; import java.security.AccessControlException; import java.security.Principal; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; -import java.util.List; import javax.security.auth.Subject; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; -import ca.nrc.cadc.ac.GroupAlreadyExistsException; -import ca.nrc.cadc.ac.GroupNotFoundException; -import ca.nrc.cadc.ac.MemberAlreadyExistsException; -import ca.nrc.cadc.ac.MemberNotFoundException; 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.UserPersistence; import ca.nrc.cadc.net.TransientException; -public abstract class GroupsAction +public abstract class UsersAction implements PrivilegedExceptionAction<Object> { - private static final Logger log = Logger.getLogger(GroupsAction.class); - protected GroupLogInfo logInfo; + private static final Logger log = Logger.getLogger(UsersAction.class); + protected UserLogInfo logInfo; protected HttpServletResponse response; - GroupsAction(GroupLogInfo logInfo) + UsersAction(UserLogInfo logInfo) { this.logInfo = logInfo; } @@ -144,20 +138,6 @@ public abstract class GroupsAction this.logInfo.setMessage(message); sendError(400, message); } - catch (MemberNotFoundException e) - { - log.debug(e.getMessage(), e); - String message = "Member not found: " + e.getMessage(); - this.logInfo.setMessage(message); - sendError(404, message); - } - catch (GroupNotFoundException e) - { - log.debug(e.getMessage(), e); - String message = "Group not found: " + e.getMessage(); - this.logInfo.setMessage(message); - sendError(404, message); - } catch (UserNotFoundException e) { log.debug(e.getMessage(), e); @@ -165,20 +145,6 @@ public abstract class GroupsAction this.logInfo.setMessage(message); sendError(404, message); } - catch (MemberAlreadyExistsException e) - { - log.debug(e.getMessage(), e); - String message = "Member already exists: " + e.getMessage(); - this.logInfo.setMessage(message); - sendError(409, message); - } - catch (GroupAlreadyExistsException e) - { - log.debug(e.getMessage(), e); - String message = "Group already exists: " + e.getMessage(); - this.logInfo.setMessage(message); - sendError(409, message); - } catch (UnsupportedOperationException e) { log.debug(e.getMessage(), e); @@ -227,23 +193,15 @@ public abstract class GroupsAction } } - <T extends Principal> GroupPersistence<T> getGroupPersistence() - { - PluginFactory pluginFactory = new PluginFactory(); - return pluginFactory.getGroupPersistence(); - } - <T extends Principal> UserPersistence<T> getUserPersistence() { PluginFactory pluginFactory = new PluginFactory(); return pluginFactory.getUserPersistence(); } - protected void logGroupInfo(String groupID, List<String> deletedMembers, List<String> addedMembers) + protected void logUserInfo(String userName) { - this.logInfo.groupID = groupID; - this.logInfo.addedMembers = addedMembers; - this.logInfo.deletedMembers = deletedMembers; + this.logInfo.userName = userName; } } diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersActionFactory.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersActionFactory.java old mode 100755 new mode 100644 index 9263dde6..1a431670 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersActionFactory.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersActionFactory.java @@ -66,26 +66,27 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.users; +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.auth.NumericPrincipal; +import ca.nrc.cadc.util.StringUtil; import java.io.IOException; import java.net.URL; -import java.net.URLDecoder; - +import java.security.Principal; +import javax.security.auth.x500.X500Principal; import javax.servlet.http.HttpServletRequest; - import org.apache.log4j.Logger; -import ca.nrc.cadc.util.StringUtil; - -public class GroupsActionFactory +public class UsersActionFactory { - private static final Logger log = Logger.getLogger(GroupsActionFactory.class); + private static final Logger log = Logger.getLogger(UsersActionFactory.class); - static GroupsAction getGroupsAction(HttpServletRequest request, GroupLogInfo logInfo) + static UsersAction getUsersAction(HttpServletRequest request, UserLogInfo logInfo) throws IOException { - GroupsAction action = null; + UsersAction action = null; String method = request.getMethod(); String path = request.getPathInfo(); log.debug("method: " + method); @@ -116,24 +117,25 @@ public class GroupsActionFactory { if (method.equals("GET")) { - action = new GetGroupNamesAction(logInfo); + action = new GetUserNamesAction(logInfo); } else if (method.equals("PUT")) { - action = new CreateGroupAction(logInfo, request.getInputStream()); + action = new CreateUserAction(logInfo, request.getInputStream()); } } else if (segments.length == 1) { - String groupName = segments[0]; + String userName = segments[0]; + User user = getUserFromUsername(userName); if (method.equals("GET")) { - action = new GetGroupAction(logInfo, groupName); + action = new GetUserAction(logInfo, user.getUserID()); } else if (method.equals("DELETE")) { - action = new DeleteGroupAction(logInfo, groupName); + action = new DeleteUserAction(logInfo, user.getUserID()); } else if (method.equals("POST")) { @@ -152,41 +154,8 @@ public class GroupsActionFactory sb.append("/"); sb.append(path); - action = new ModifyGroupAction(logInfo, groupName, sb.toString(), - request.getInputStream()); - } - } - else if (segments.length == 3) - { - String groupName = segments[0]; - String memberCategory = segments[1]; - if (method.equals("PUT")) - { - if (memberCategory.equals("groupMembers")) - { - String groupMemberName = segments[2]; - action = new AddGroupMemberAction(logInfo, groupName, groupMemberName); - } - else if (memberCategory.equals("userMembers")) - { - String userMemberID = URLDecoder.decode(segments[2], "UTF-8"); - String userMemberIDType = request.getParameter("idType"); - action = new AddUserMemberAction(logInfo, groupName, userMemberID, userMemberIDType); - } - } - else if (method.equals("DELETE")) - { - if (memberCategory.equals("groupMembers")) - { - String groupMemberName = segments[2]; - action = new RemoveGroupMemberAction(logInfo, groupName, groupMemberName); - } - else if (memberCategory.equals("userMembers")) - { - String memberUserID = URLDecoder.decode(segments[2], "UTF-8"); - String memberUserIDType = request.getParameter("idType"); - action = new RemoveUserMemberAction(logInfo, groupName, memberUserID, memberUserIDType); - } + action = new ModifyUserAction(logInfo, user.getUserID(), sb.toString(), + request.getInputStream()); } } @@ -195,7 +164,23 @@ public class GroupsActionFactory log.debug("Returning action: " + action.getClass()); return action; } - throw new IllegalArgumentException("Bad groups request: " + method + " on " + path); + throw new IllegalArgumentException("Bad users request: " + method + " on " + path); } + private static User<? extends Principal> getUserFromUsername(final String userName) + { + try + { + return new User(new X500Principal(userName)); + } + catch (IllegalArgumentException e) {} + + try + { + return new User(new NumericPrincipal(Long.parseLong(userName))); + } + catch (NumberFormatException e) {} + + return new User((new HttpPrincipal(userName))); + } } 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 old mode 100755 new mode 100644 index dd62ed5c..ef2345d7 --- 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 @@ -66,7 +66,7 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web; +package ca.nrc.cadc.ac.server.web.users; import java.io.IOException; @@ -79,9 +79,9 @@ import org.apache.log4j.Logger; import ca.nrc.cadc.auth.AuthenticationUtil; -public class GroupsServlet extends HttpServlet +public class UsersServlet extends HttpServlet { - private static final Logger log = Logger.getLogger(GroupsServlet.class); + private static final Logger log = Logger.getLogger(UsersServlet.class); /** * Create a GroupAction and run the action safely. @@ -90,13 +90,13 @@ public class GroupsServlet extends HttpServlet throws IOException { long start = System.currentTimeMillis(); - GroupLogInfo logInfo = new GroupLogInfo(request); + UserLogInfo logInfo = new UserLogInfo(request); try { log.info(logInfo.start()); Subject subject = AuthenticationUtil.getSubject(request); logInfo.setSubject(subject); - GroupsAction action = GroupsActionFactory.getGroupsAction(request, logInfo); + UsersAction action = UsersActionFactory.getUsersAction(request, logInfo); action.doAction(subject, response); } catch (IllegalArgumentException e) 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 abce3f78..72148d0e 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 @@ -119,15 +119,52 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest testUserDN = "uid=cadcdaotest1," + config.getUsersDN(); } - LdapUserDAO<X500Principal> getUserDAO() + LdapUserDAO getUserDAO() { - return new LdapUserDAO<X500Principal>(config); + return new LdapUserDAO(config); + } + + String getUserID() + { + return "CadcDaoTestUser-" + System.currentTimeMillis(); } /** - * Test of getUser method, of class LdapUserDAO. + * Test of addUser method, of class LdapUserDAO. */ @Test + public void testAddUser() throws Exception + { + final User<HttpPrincipal> newUser = new User<HttpPrincipal>(new HttpPrincipal(getUserID())); + newUser.details.add(new PersonalDetails("foo", "bar")); + + Subject subject = new Subject(); + subject.getPrincipals().add(testUser.getUserID()); + + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + User<? extends Principal> actual = getUserDAO().addUser(newUser); + check(newUser, actual); + + return null; + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + } + }); + } + + /** + * Test of getUser method, of class LdapUserDAO. + */ +// @Test public void testGetUser() throws Exception { Subject subject = new Subject(); @@ -157,7 +194,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest /** * Test of getUserGroups method, of class LdapUserDAO. */ - @Test +// @Test public void testGetUserGroups() throws Exception { Subject subject = new Subject(); @@ -195,7 +232,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest /** * Test of getUserGroups method, of class LdapUserDAO. */ - @Test +// @Test public void testIsMember() throws Exception { Subject subject = new Subject(); @@ -228,7 +265,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest /** * Test of getMember. */ - @Test +// @Test public void testGetMember() throws Exception { Subject subject = new Subject(); diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java new file mode 100644 index 00000000..7b07355d --- /dev/null +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java @@ -0,0 +1,268 @@ +/** + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2014. (c) 2014. + * 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.server.web.users; + +import ca.nrc.cadc.ac.server.web.RemoveUserMemberAction; +import ca.nrc.cadc.util.Log4jInit; +import javax.servlet.http.HttpServletRequest; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Test; + + +public class UserActionFactoryTest +{ + private final static Logger log = Logger.getLogger(UserActionFactoryTest.class); + + public UserActionFactoryTest() + { + Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); + } + + @Test + public void testCreateCreateUserAction() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.expect(request.getPathInfo()).andReturn(""); + EasyMock.expect(request.getMethod()).andReturn("PUT"); + EasyMock.expect(request.getInputStream()).andReturn(null); + EasyMock.replay(request); + UsersAction action = UsersActionFactory.getUsersAction(request, null); + EasyMock.verify(request); + Assert.assertTrue("Wrong action", action instanceof CreateUserAction); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testCreateDeleteUserAction() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.expect(request.getPathInfo()).andReturn("userName"); + EasyMock.expect(request.getMethod()).andReturn("DELETE"); + EasyMock.replay(request); + UsersAction action = UsersActionFactory.getUsersAction(request, null); + EasyMock.verify(request); + Assert.assertTrue("Wrong action", action instanceof DeleteUserAction); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testCreateGetUserAction() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.expect(request.getPathInfo()).andReturn("userName"); + EasyMock.expect(request.getMethod()).andReturn("GET"); + EasyMock.replay(request); + UsersAction action = UsersActionFactory.getUsersAction(request, null); + EasyMock.verify(request); + Assert.assertTrue("Wrong action", action instanceof GetUserAction); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testCreateGetUserNamesAction() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.expect(request.getPathInfo()).andReturn(""); + EasyMock.expect(request.getMethod()).andReturn("GET"); + EasyMock.replay(request); + UsersAction action = UsersActionFactory.getUsersAction(request, null); + EasyMock.verify(request); + Assert.assertTrue("Wrong action", action instanceof GetUserNamesAction); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testCreateModifyUserAction() + { + try + { + StringBuffer sb = new StringBuffer(); + sb.append("http://localhost:80/ac/users/foo"); + + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.expect(request.getPathInfo()).andReturn("userName"); + EasyMock.expect(request.getMethod()).andReturn("POST"); + EasyMock.expect(request.getRequestURL()).andReturn(sb); + EasyMock.expect(request.getContextPath()).andReturn(""); + EasyMock.expect(request.getServletPath()).andReturn(""); + EasyMock.expect(request.getInputStream()).andReturn(null); + EasyMock.replay(request); + UsersAction action = UsersActionFactory.getUsersAction(request, null); + EasyMock.verify(request); + Assert.assertTrue("Wrong action", action instanceof ModifyUserAction); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testBadRequests() + { + try + { + TestRequest[] testRequests = + { + new TestRequest("", "POST"), + new TestRequest("", "DELETE"), + new TestRequest("", "HEAD"), + }; + + for (TestRequest testRequest : testRequests) + { + + log.debug("Testing: " + testRequest); + + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.expect(request.getPathInfo()).andReturn(testRequest.path); + EasyMock.expect(request.getMethod()).andReturn(testRequest.method); + if (testRequest.paramName != null) + { + EasyMock.expect(request.getParameter(testRequest.paramName)).andReturn(testRequest.paramValue); + } + EasyMock.replay(request); + try + { + UsersActionFactory.getUsersAction(request, null); + Assert.fail("Should have been a bad request: " + testRequest.method + " on " + testRequest.path); + } + catch (IllegalArgumentException e) + { + // expected + } + EasyMock.verify(request); + } + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + private class TestRequest + { + public String path; + public String method; + public String paramName; + public String paramValue; + + public TestRequest(String path, String method) + { + this(path, method, null, null); + } + public TestRequest(String path, String method, String paramName, String paramValue) + { + this.path = path; + this.method = method; + this.paramName = paramName; + this.paramValue = paramValue; + } + @Override + public String toString() + { + return method + " on path " + path + + ((paramName == null) ? "" : "?" + paramName + "=" + paramValue); + } + + } + +} diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UsersActionTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UsersActionTest.java new file mode 100644 index 00000000..8c185028 --- /dev/null +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UsersActionTest.java @@ -0,0 +1,220 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2014. (c) 2014. + * 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/>. + * + * $Revision: 4 $ + * + ************************************************************************ + */ +package ca.nrc.cadc.ac.server.web.users; + +import ca.nrc.cadc.ac.UserNotFoundException; +import ca.nrc.cadc.net.TransientException; +import ca.nrc.cadc.util.Log4jInit; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.security.AccessControlException; +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.Test; +import static org.junit.Assert.*; + +/** + * + * @author jburke + */ +public class UsersActionTest +{ + private final static Logger log = Logger.getLogger(UsersActionTest.class); + + @BeforeClass + public static void setUpClass() + { + Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); + } + + @Test + public void testDoActionAccessControlException() throws Exception + { + String message = "Permission Denied"; + int responseCode = 403; + Exception e = new AccessControlException(""); + testDoAction(message, responseCode, e); + } + + @Test + public void testDoActionIllegalArgumentException() throws Exception + { + String message = "message"; + int responseCode = 400; + Exception e = new IllegalArgumentException("message"); + testDoAction(message, responseCode, e); + } + + @Test + public void testDoActionUserNotFoundException() throws Exception + { + String message = "User not found: foo"; + int responseCode = 404; + Exception e = new UserNotFoundException("foo"); + testDoAction(message, responseCode, e); + } + + @Test + public void testDoActionUnsupportedOperationException() throws Exception + { + String message = "Not yet implemented."; + int responseCode = 501; + Exception e = new UnsupportedOperationException(); + testDoAction(message, responseCode, e); + } + + @Test + public void testDoActionTransientException() throws Exception + { + try + { + HttpServletResponse response = EasyMock.createMock(HttpServletResponse.class); + EasyMock.expect(response.isCommitted()).andReturn(Boolean.FALSE); + response.setContentType("text/plain"); + EasyMock.expectLastCall().once(); + EasyMock.expect(response.getWriter()).andReturn(new PrintWriter(new StringWriter())); + EasyMock.expectLastCall().once(); + response.setStatus(503); + EasyMock.expectLastCall().once(); + EasyMock.replay(response); + + UserLogInfo logInfo = EasyMock.createMock(UserLogInfo.class); + logInfo.setSuccess(false); + EasyMock.expectLastCall().once(); + logInfo.setMessage("Internal Transient Error: foo"); + EasyMock.expectLastCall().once(); + EasyMock.replay(logInfo); + + UsersActionImpl action = new UsersActionImpl(logInfo); + action.setException(new TransientException("foo")); + action.doAction(null, response); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + fail("unexpected error: " + t.getMessage()); + } + } + + private void testDoAction(String message, int responseCode, Exception e) + throws Exception + { + try + { + HttpServletResponse response = EasyMock.createMock(HttpServletResponse.class); + EasyMock.expect(response.isCommitted()).andReturn(Boolean.FALSE); + response.setContentType("text/plain"); + EasyMock.expectLastCall().once(); + EasyMock.expect(response.getWriter()).andReturn(new PrintWriter(new StringWriter())); + EasyMock.expectLastCall().once(); + response.setStatus(responseCode); + EasyMock.expectLastCall().once(); + EasyMock.replay(response); + + UserLogInfo logInfo = EasyMock.createMock(UserLogInfo.class); + logInfo.setMessage(message); + EasyMock.expectLastCall().once(); + EasyMock.replay(logInfo); + + UsersActionImpl action = new UsersActionImpl(logInfo); + action.setException(e); + action.doAction(null, response); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + fail("unexpected error: " + t.getMessage()); + } + } + + public class UsersActionImpl extends UsersAction + { + Exception exception; + + public UsersActionImpl(UserLogInfo logInfo) + { + super(logInfo); + } + + public Object run() throws Exception + { + throw exception; + } + + public void setException(Exception e) + { + this.exception = e; + } + } + +} -- GitLab