diff --git a/projects/cadcAccessControl-Server/build.xml b/projects/cadcAccessControl-Server/build.xml index 0630318fe0877df1c73754d6d9b5f658131598f6..6f8dc7a662b3fc95e0a9a4c1c401868a507ccf83 100644 --- a/projects/cadcAccessControl-Server/build.xml +++ b/projects/cadcAccessControl-Server/build.xml @@ -67,83 +67,70 @@ ************************************************************************ --> - -<!DOCTYPE project> <project name="cadcAccessControl-Server" default="build" basedir="."> - <property environment="env"/> - <property file="local.build.properties" /> - - <!-- site-specific build properties or overrides of values in opencadc.properties --> - <property file="${env.CADC_PREFIX}/etc/local.properties" /> - - <!-- site-specific targets, e.g. install, cannot duplicate those in opencadc.targets.xml --> - <import file="${env.CADC_PREFIX}/etc/local.targets.xml" optional="true" /> - - <!-- default properties and targets --> - <property file="${env.CADC_PREFIX}/etc/opencadc.properties" /> - <import file="${env.CADC_PREFIX}/etc/opencadc.targets.xml"/> - - <!-- developer convenience: place for extra targets and properties --> - <import file="extras.xml" optional="true" /> - - <property name="project" value="cadcAccessControl-Server" /> - - <property name="cadcAccessControl" value="${lib}/cadcAccessControl.jar" /> - <property name="cadcLog" value="${lib}/cadcLog.jar" /> - <property name="cadcRegistry" value="${lib}/cadcRegistryClient.jar" /> - <property name="cadcUtil" value="${lib}/cadcUtil.jar" /> - <property name="cadcUWS" value="${lib}/cadcUWS.jar" /> - <property name="wsUtil" value="${lib}/wsUtil.jar" /> - - <property name="javacsv" value="${ext.lib}/javacsv.jar" /> - <property name="jdom2" value="${ext.lib}/jdom2.jar" /> - <property name="log4j" value="${ext.lib}/log4j.jar" /> - <property name="servlet" value="${ext.lib}/servlet-api.jar" /> - <property name="unboundid" value="${ext.lib}/unboundid-ldapsdk-se.jar" /> - <property name="xerces" value="${ext.lib}/xerces.jar" /> - - <property name="jars" value="${javacsv}:${jdom2}:${log4j}:${servlet}:${unboundid}:${xerces}:${cadcAccessControl}:${cadcLog}:${cadcRegistry}:${cadcUtil}:${cadcUWS}:${wsUtil}" /> - - <target name="build" depends="compile"> - <jar jarfile="${build}/lib/${project}.jar" - basedir="${build}/class" - update="no"> - <include name="ca/nrc/cadc/**" /> - </jar> - </target> - - <!-- JAR files needed to run the test suite --> - <property name="json" value="${ext.lib}/json.jar" /> - <property name="easyMock" value="${ext.dev}/easymock.jar" /> - <property name="junit" value="${ext.dev}/junit.jar" /> - <property name="xmlunit" value="${ext.dev}/xmlunit.jar" /> - <property name="cglib" value="${ext.dev}/cglib.jar" /> - <property name="objenesis" value="${ext.dev}/objenesis.jar" /> - <property name="asm" value="${ext.dev}/asm.jar" /> - - <property name="testingJars" value="${jars}:${json}:${easyMock}:${junit}:${xmlunit}:${cglib}:${asm}:${objenesis}" /> - - <target name="resources"> - <copy todir="${build}/class"> - <fileset dir="config"> - <include name="**.properties" /> - </fileset> - </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.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> + <property environment="env"/> + <property file="local.build.properties"/> + + <!-- site-specific build properties or overrides of values in opencadc.properties --> + <property file="${env.CADC_PREFIX}/etc/local.properties"/> + + <!-- site-specific targets, e.g. install, cannot duplicate those in opencadc.targets.xml --> + <import file="${env.CADC_PREFIX}/etc/local.targets.xml" optional="true"/> + + <!-- default properties and targets --> + <property file="${env.CADC_PREFIX}/etc/opencadc.properties"/> + <import file="${env.CADC_PREFIX}/etc/opencadc.targets.xml"/> + + <!-- developer convenience: place for extra targets and properties --> + <import file="extras.xml" optional="true"/> + + <property name="project" value="cadcAccessControl-Server"/> + + <property name="cadcAccessControl" value="${lib}/cadcAccessControl.jar"/> + <property name="cadcLog" value="${lib}/cadcLog.jar"/> + <property name="cadcRegistry" value="${lib}/cadcRegistryClient.jar"/> + <property name="cadcUtil" value="${lib}/cadcUtil.jar"/> + <property name="cadcUWS" value="${lib}/cadcUWS.jar"/> + <property name="wsUtil" value="${lib}/wsUtil.jar"/> + + <property name="javacsv" value="${ext.lib}/javacsv.jar"/> + <property name="jdom2" value="${ext.lib}/jdom2.jar"/> + <property name="log4j" value="${ext.lib}/log4j.jar"/> + <property name="servlet" value="${ext.lib}/servlet-api.jar"/> + <property name="unboundid" value="${ext.lib}/unboundid-ldapsdk-se.jar"/> + <property name="xerces" value="${ext.lib}/xerces.jar"/> + + <property name="jars" + value="${javacsv}:${jdom2}:${log4j}:${servlet}:${unboundid}:${xerces}:${cadcAccessControl}:${cadcLog}:${cadcRegistry}:${cadcUtil}:${cadcUWS}:${wsUtil}"/> + + <target name="build" depends="compile"> + <jar jarfile="${build}/lib/${project}.jar" + basedir="${build}/class" + update="no"> + <include name="ca/nrc/cadc/**"/> + </jar> + </target> + + <!-- JAR files needed to run the test suite --> + <property name="json" value="${ext.lib}/json.jar"/> + <property name="easyMock" value="${ext.dev}/easymock.jar"/> + <property name="junit" value="${ext.dev}/junit.jar"/> + <property name="xmlunit" value="${ext.dev}/xmlunit.jar"/> + <property name="cglib" value="${ext.dev}/cglib.jar"/> + <property name="objenesis" value="${ext.dev}/objenesis.jar"/> + <property name="asm" value="${ext.dev}/asm.jar"/> + + <property name="testingJars" + value="${jars}:${json}:${easyMock}:${junit}:${xmlunit}:${cglib}:${asm}:${objenesis}"/> + + <target name="setup-test"> + <echo>******************</echo> + <echo>******************</echo> + <echo>Don't forget to set the ca.nrc.cadc.util.PropertiesReader.dir system property first!</echo> + <echo>e.g. ant -Dca.nrc.cadc.util.PropertiesReader.dir=test clean build test</echo> + <echo>******************</echo> + <echo>******************</echo> + </target> </project> diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/PluginFactory.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/PluginFactory.java index caa18b20c505d98444c4b428ca8a8a9dad7b0aba..595e7dcf1f5d5d4f6f0ac7afae3013d0c21d385f 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/PluginFactory.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/PluginFactory.java @@ -140,9 +140,10 @@ public class PluginFactory @SuppressWarnings("unchecked") public <T extends Principal> UserPersistence<T> getUserPersistence() { - UserPersistence<T> ret = null; + UserPersistence ret = null; String name = UserPersistence.class.getName(); String cname = config.getProperty(name); + if (cname == null) { ret = new LdapUserPersistence<T>(); @@ -152,7 +153,7 @@ public class PluginFactory try { Class<?> c = Class.forName(cname); - ret = (UserPersistence<T>) c.newInstance(); + ret = (UserPersistence) c.newInstance(); } catch (Exception ex) { 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 9ae4d37f108ca3f3eb7ed11d5ab966c8e3f4ddeb..af5a6c53cdeabe0bcaed87643e93187f75ada658 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 @@ -79,7 +79,7 @@ import ca.nrc.cadc.net.TransientException; import com.unboundid.ldap.sdk.DN; -public abstract interface UserPersistence<T extends Principal> +public interface UserPersistence<T extends Principal> { /** * Get all user names. @@ -88,7 +88,7 @@ public abstract interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public Collection<String> getUserNames() + Collection<String> getUserNames() throws TransientException, AccessControlException; /** @@ -101,7 +101,7 @@ public abstract interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public abstract User<T> addUser(UserRequest<T> user) + User<T> addUser(UserRequest<T> user) throws TransientException, AccessControlException; /** @@ -115,7 +115,7 @@ public abstract interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public abstract User<T> getUser(T userID) + User<T> getUser(T userID) throws UserNotFoundException, TransientException, AccessControlException; @@ -130,7 +130,7 @@ public abstract interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public abstract User<T> modifyUser(User<T> user) + User<T> modifyUser(User<T> user) throws UserNotFoundException, TransientException, AccessControlException; @@ -143,7 +143,7 @@ public abstract interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public abstract void deleteUser(T userID) + void deleteUser(T userID) throws UserNotFoundException, TransientException, AccessControlException; @@ -160,7 +160,7 @@ public abstract interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public abstract Collection<DN> getUserGroups(T userID, boolean isAdmin) + Collection<DN> getUserGroups(T userID, boolean isAdmin) throws UserNotFoundException, TransientException, AccessControlException; @@ -176,7 +176,7 @@ public abstract interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public abstract boolean isMember(T userID, String groupID) + boolean isMember(T userID, String groupID) throws UserNotFoundException, TransientException, AccessControlException; } 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 index ad3c1b0be764f0f490d8a0a47c1b03d057c4a7b7..81d25f43c80b34d1917a919930cce9af6e61d655 100644 --- 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 @@ -77,7 +77,7 @@ import ca.nrc.cadc.ac.xml.UserWriter; import java.security.Principal; -public class CreateUserAction extends UsersAction +public class CreateUserAction<T extends Principal> extends UsersAction { private final InputStream inputStream; @@ -90,11 +90,10 @@ public class CreateUserAction extends UsersAction public Object run() throws Exception { - UserPersistence userPersistence = getUserPersistence(); - UserRequest userRequest = UserRequestReader.read(this.inputStream); - User<? extends Principal> newUser = userPersistence.addUser(userRequest); - this.response.setContentType(acceptedContentType); - writeUser(newUser, this.response.getWriter()); + UserPersistence<Principal> userPersistence = getUserPersistence(); + UserRequest<Principal> userRequest = readUserRequest(this.inputStream); + User<Principal> newUser = userPersistence.addUser(userRequest); + writeUser(newUser); logUserInfo(newUser.getUserID().getName()); 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 index 22f9cf6306bb2ef555e8310de71a4b4506bad74a..d4ee1d0efe03a6bf8fecc24790caa7e0636f07e4 100644 --- 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 @@ -69,10 +69,10 @@ import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.server.UserPersistence; -import ca.nrc.cadc.ac.xml.UserWriter; import java.security.Principal; + public class GetUserAction extends UsersAction { private final Principal userID; @@ -83,13 +83,11 @@ public class GetUserAction extends UsersAction this.userID = userID; } - public Object run() - throws Exception + public Object run() throws Exception { - UserPersistence userPersistence = getUserPersistence(); - User<? extends Principal> user = userPersistence.getUser(userID); - this.response.setContentType(acceptedContentType); - writeUser(user, this.response.getWriter()); + UserPersistence<Principal> userPersistence = getUserPersistence(); + User<Principal> user = userPersistence.getUser(userID); + writeUser(user); return null; } diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersAction.java index 5453746623b4a2bf9f3513967a28ee776ac383c1..3a83c96e67cbca4221a40787f16bd00d796be666 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 @@ -69,7 +69,7 @@ package ca.nrc.cadc.ac.server.web.users; import java.io.IOException; -import java.io.OutputStream; +import java.io.InputStream; import java.io.Writer; import java.security.AccessControlException; import java.security.Principal; @@ -80,6 +80,7 @@ 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; @@ -200,6 +201,7 @@ public abstract class UsersAction } } + @SuppressWarnings("unchecked") <T extends Principal> UserPersistence<T> getUserPersistence() { PluginFactory pluginFactory = new PluginFactory(); @@ -216,10 +218,80 @@ public abstract class UsersAction this.acceptedContentType = acceptedContentType; } - protected final <T extends Principal> void writeUser(final User<T> user, - final Writer writer) + /** + * Read a user request (User pending approval) from the HTTP Request's + * stream. + * + * @param inputStream The Input Stream to read from. + * @return User Request instance. + * @throws IOException Any reading errors. + */ + protected final UserRequest<Principal> readUserRequest( + final InputStream inputStream) throws IOException + { + final UserRequest<Principal> userRequest; + + if (acceptedContentType.equals(DEFAULT_CONTENT_TYPE)) + { + userRequest = ca.nrc.cadc.ac.xml.UserRequestReader.read(inputStream); + } + else if (acceptedContentType.equals(JSON_CONTENT_TYPE)) + { + userRequest = + ca.nrc.cadc.ac.json.UserRequestReader.read(inputStream); + } + else + { + // Should never happen. + throw new IOException("Unknown content being asked for: " + + acceptedContentType); + } + + return userRequest; + } + + /** + * Read a user from the HTTP Request's stream. + * + * @param inputStream The Input Stream to read from. + * @return User instance. + * @throws IOException Any reading error(s) + */ + protected final User<Principal> readUser( + final InputStream inputStream) throws IOException + { + final User<Principal> user; + + if (acceptedContentType.equals(DEFAULT_CONTENT_TYPE)) + { + user = ca.nrc.cadc.ac.xml.UserReader.read(inputStream); + } + else if (acceptedContentType.equals(JSON_CONTENT_TYPE)) + { + user = ca.nrc.cadc.ac.json.UserReader.read(inputStream); + } + else + { + // Should never happen. + throw new IOException("Unknown content being asked for: " + + acceptedContentType); + } + + return user; + } + + /** + * Write a user to the response's writer. + * + * @param user The user object to marshall and write out. + * @throws IOException Any writing errors. + */ + protected final <T extends Principal> void writeUser(final User<T> user) throws IOException { + response.setContentType(acceptedContentType); + final Writer writer = response.getWriter(); + if (acceptedContentType.equals(DEFAULT_CONTENT_TYPE)) { ca.nrc.cadc.ac.xml.UserWriter.write(user, writer); 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 index d97c4b73584a07d302debc1f7a16df9293e95f12..d1f1a9b4f5fd65f36d5bc8cadb214cc89c15359a 100644 --- 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 @@ -75,28 +75,23 @@ import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.auth.OpenIdPrincipal; import ca.nrc.cadc.util.StringUtil; + import java.io.IOException; import java.net.URL; import java.security.Principal; import javax.security.auth.x500.X500Principal; import javax.servlet.http.HttpServletRequest; + import org.apache.log4j.Logger; -import ca.nrc.cadc.ac.server.web.AddGroupMemberAction; -import ca.nrc.cadc.ac.server.web.AddUserMemberAction; -import ca.nrc.cadc.ac.server.web.DeleteGroupAction; -import ca.nrc.cadc.ac.server.web.GetGroupAction; -import ca.nrc.cadc.ac.server.web.ModifyGroupAction; -import ca.nrc.cadc.ac.server.web.RemoveGroupMemberAction; -import ca.nrc.cadc.ac.server.web.RemoveUserMemberAction; -import ca.nrc.cadc.util.StringUtil; public class UsersActionFactory { - private static final Logger log = Logger.getLogger(UsersActionFactory.class); + private static final Logger log = Logger + .getLogger(UsersActionFactory.class); static UsersAction getUsersAction(HttpServletRequest request, UserLogInfo logInfo) - throws IOException + throws IOException { UsersAction action = null; String method = request.getMethod(); @@ -133,7 +128,8 @@ public class UsersActionFactory } else if (method.equals("PUT")) { - action = new CreateUserAction(logInfo, request.getInputStream()); + action = new CreateUserAction(logInfo, request + .getInputStream()); } } @@ -151,7 +147,8 @@ public class UsersActionFactory } else if (method.equals("POST")) { - final URL requestURL = new URL(request.getRequestURL().toString()); + final URL requestURL = new URL(request.getRequestURL() + .toString()); final StringBuilder sb = new StringBuilder(); sb.append(requestURL.getProtocol()); sb.append("://"); @@ -166,7 +163,8 @@ public class UsersActionFactory sb.append("/"); sb.append(path); - action = new ModifyUserAction(logInfo, user.getUserID(), sb.toString(), + action = new ModifyUserAction(logInfo, user.getUserID(), sb + .toString(), request.getInputStream()); } } @@ -180,8 +178,10 @@ public class UsersActionFactory throw new IllegalArgumentException(error); } - private static User<? extends Principal> getUser(final String userName, final String idType, - final String method, final String path) + private static User<? extends Principal> getUser(final String userName, + final String idType, + final String method, + final String path) { if (idType == null || idType.isEmpty()) { @@ -189,27 +189,28 @@ public class UsersActionFactory } else if (idType.equals(IdentityType.USERNAME.getValue())) { - return new User(new HttpPrincipal(userName)); + return new User<HttpPrincipal>(new HttpPrincipal(userName)); } else if (idType.equals(IdentityType.X500.getValue())) { - return new User(new X500Principal(userName)); + return new User<X500Principal>(new X500Principal(userName)); } else if (idType.equals(IdentityType.UID.getValue())) { - return new User(new NumericPrincipal(Long.parseLong(userName))); + return new User<NumericPrincipal>(new NumericPrincipal( + Long.parseLong(userName))); } else if (idType.equals(IdentityType.OPENID.getValue())) { - return new User(new OpenIdPrincipal(userName)); + return new User<OpenIdPrincipal>(new OpenIdPrincipal(userName)); } else if (idType.equals(IdentityType.COOKIE.getValue())) { - return new User(new CookiePrincipal(userName)); + return new User<CookiePrincipal>(new CookiePrincipal(userName)); } else { - final String error = "Bad users request: " + method + " on " + path + + final String error = "Bad users request: " + method + " on " + path + " because of unknown principal type " + idType; throw new IllegalArgumentException(error); } diff --git a/projects/cadcAccessControl-Server/test/LdapConfig.test.properties b/projects/cadcAccessControl-Server/test/LdapConfig.test.properties index d576adc7e06cd7829edc3d1b980dae43c2795c95..0d3bc21ab631c1065379ffda2e5f38f005ed90b4 100644 --- a/projects/cadcAccessControl-Server/test/LdapConfig.test.properties +++ b/projects/cadcAccessControl-Server/test/LdapConfig.test.properties @@ -3,6 +3,7 @@ server = proc5-03.cadc.dao.nrc.ca port = 636 proxyUser = webproxy usersDn = ou=Users,ou=ds,dc=canfar,dc=net +userRequestsDN = ou=UserRequests,ou=ds,dc=canfar,dc=net 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 diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserActionTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserActionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e116d69fc410b6e5c740bec4259f440753f03bd7 --- /dev/null +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserActionTest.java @@ -0,0 +1,164 @@ +/* + ************************************************************************ + ******************* 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.server.web.users; + +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.server.UserPersistence; +import ca.nrc.cadc.auth.HttpPrincipal; +import org.junit.Test; + +import javax.servlet.http.HttpServletResponse; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; + +import static org.easymock.EasyMock.*; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; + +public class GetUserActionTest +{ + @Test + public void writeUserXML() throws Exception + { + final HttpServletResponse mockResponse = + createMock(HttpServletResponse.class); + final UserPersistence<HttpPrincipal> mockUserPersistence = + createMock(UserPersistence.class); + final HttpPrincipal userID = new HttpPrincipal("CADCtest"); + + final GetUserAction testSubject = new GetUserAction(null, userID) + { + @Override + UserPersistence<HttpPrincipal> getUserPersistence() + { + return mockUserPersistence; + } + }; + + final User<HttpPrincipal> user = new User<HttpPrincipal>(userID); + final Writer writer = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(writer); + + expect(mockUserPersistence.getUser(userID)).andReturn(user).once(); + expect(mockResponse.getWriter()).andReturn(printWriter).once(); + mockResponse.setContentType("text/xml"); + expectLastCall().once(); + + replay(mockResponse, mockUserPersistence); + + testSubject.doAction(null, mockResponse); + + assertEquals("Wrong XML output.", + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + + "<user>\r\n" + + " <userID>\r\n" + + " <identity type=\"HTTP\">CADCtest</identity>\r\n" + + " </userID>\r\n" + + "</user>\r\n", writer.toString()); + verify(mockResponse, mockUserPersistence); + } + + @Test + public void writeUserJSON() throws Exception + { + final HttpServletResponse mockResponse = + createMock(HttpServletResponse.class); + final UserPersistence<HttpPrincipal> mockUserPersistence = + createMock(UserPersistence.class); + final HttpPrincipal userID = new HttpPrincipal("CADCtest"); + + final GetUserAction testSubject = new GetUserAction(null, userID) + { + @Override + UserPersistence<HttpPrincipal> getUserPersistence() + { + return mockUserPersistence; + } + }; + + testSubject.setAcceptedContentType(UsersAction.JSON_CONTENT_TYPE); + + final User<HttpPrincipal> user = new User<HttpPrincipal>(userID); + final Writer writer = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(writer); + + expect(mockUserPersistence.getUser(userID)).andReturn(user).once(); + expect(mockResponse.getWriter()).andReturn(printWriter).once(); + mockResponse.setContentType("application/json"); + expectLastCall().once(); + + replay(mockResponse, mockUserPersistence); + testSubject.doAction(null, mockResponse); + + assertEquals("Wrong JSON output.", + "{\"user\":{\"userID\":{\"identity\":{\"name\":\"CADCtest\",\"type\":\"HTTP\"}}}}", + writer.toString()); + verify(mockResponse, mockUserPersistence); + } +} 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 index 67cba1aac80b91a28c96d039de47eded5cd802a0..9f68864b52147a94be6ea974d9ae7fd5cdfe178c 100644 --- 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 @@ -70,18 +70,22 @@ package ca.nrc.cadc.ac.server.web.users; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; +import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.util.Log4jInit; import java.io.*; import java.security.AccessControlException; +import java.security.Principal; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Level; import org.apache.log4j.Logger; -import org.easymock.EasyMock; + +import static org.easymock.EasyMock.*; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.*; @@ -99,59 +103,6 @@ public class UsersActionTest Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); } - @Test - public void writeUserXML() throws Exception - { - final UsersAction usersAction = new UsersAction(null) - { - @Override - public Object run() throws Exception - { - // Do nothing. - return null; - } - }; - - final User<HttpPrincipal> user = - new User<HttpPrincipal>(new HttpPrincipal("CADCtest")); - final Writer writer = new StringWriter(); - - usersAction.writeUser(user, writer); - - assertEquals("Wrong XML output.", - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + - "<user>\r\n" + - " <userID>\r\n" + - " <identity type=\"HTTP\">CADCtest</identity>\r\n" + - " </userID>\r\n" + - "</user>\r\n", writer.toString()); - } - - @Test - public void writeUserJSON() throws Exception - { - final UsersAction usersAction = new UsersAction(null) - { - @Override - public Object run() throws Exception - { - // Do nothing. - return null; - } - }; - - final User<HttpPrincipal> user = - new User<HttpPrincipal>(new HttpPrincipal("CADCtest")); - final Writer writer = new StringWriter(); - - usersAction.setAcceptedContentType(UsersAction.JSON_CONTENT_TYPE); - usersAction.writeUser(user, writer); - - assertEquals("Wrong JSON output.", - "{\"user\":{\"userID\":{\"identity\":{\"name\":\"CADCtest\",\"type\":\"HTTP\"}}}}", - writer.toString()); - } - @Test public void testDoActionAccessControlException() throws Exception { @@ -191,69 +142,52 @@ public class UsersActionTest @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()); - } + HttpServletResponse response = createMock(HttpServletResponse.class); + expect(response.isCommitted()).andReturn(Boolean.FALSE); + response.setContentType("text/plain"); + expectLastCall().once(); + expect(response.getWriter()) + .andReturn(new PrintWriter(new StringWriter())).once(); + + response.setStatus(503); + expectLastCall().once(); + replay(response); + + UserLogInfo logInfo = createMock(UserLogInfo.class); + logInfo.setSuccess(false); + expectLastCall().once(); + logInfo.setMessage("Internal Transient Error: foo"); + expectLastCall().once(); + replay(logInfo); + + UsersActionImpl action = new UsersActionImpl(logInfo); + action.setException(new TransientException("foo")); + action.doAction(null, response); } 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()); - } + HttpServletResponse response = + createMock(HttpServletResponse.class); + expect(response.isCommitted()).andReturn(Boolean.FALSE); + response.setContentType("text/plain"); + expectLastCall().once(); + expect(response.getWriter()) + .andReturn(new PrintWriter(new StringWriter())).once(); + + response.setStatus(responseCode); + expectLastCall().once(); + replay(response); + + UserLogInfo logInfo = createMock(UserLogInfo.class); + logInfo.setMessage(message); + expectLastCall().once(); + replay(logInfo); + + UsersActionImpl action = new UsersActionImpl(logInfo); + action.setException(e); + action.doAction(null, response); } public class UsersActionImpl extends UsersAction diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserRequest.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserRequest.java index fea1d0be2502e40f5ae6d99d13f98ef1fb7d98ee..d1c28cfac115e291be92c9fc60618f32de33113f 100644 --- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserRequest.java +++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserRequest.java @@ -100,4 +100,27 @@ public class UserRequest<T extends Principal> return this.password; } + @Override + public boolean equals(Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + + UserRequest<?> that = (UserRequest<?>) o; + + return user.equals(that.user); + + } + + @Override + public int hashCode() + { + return user.hashCode(); + } } diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/json/UserReader.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/json/UserReader.java index d91932a3adebbb66544ed971821ef3a5819dbaa5..b6aedd7f92293b5f7c49580ff44fd5ef20078567 100755 --- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/json/UserReader.java +++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/json/UserReader.java @@ -91,8 +91,8 @@ public class UserReader * @throws ReaderException * @throws IOException */ - public static User<? extends Principal> read(InputStream in) - throws ReaderException, IOException + public static User<Principal> read(InputStream in) + throws IOException { if (in == null) { @@ -113,8 +113,8 @@ public class UserReader * @throws ReaderException * @throws IOException */ - public static User<? extends Principal> read(Reader reader) - throws ReaderException, IOException + public static User<Principal> read(Reader reader) + throws IOException { if (reader == null) { @@ -135,8 +135,8 @@ public class UserReader * @throws ReaderException * @throws IOException */ - public static User<? extends Principal> read(String json) - throws ReaderException, IOException + public static User<Principal> read(String json) + throws IOException { if (json == null || json.isEmpty()) { @@ -156,7 +156,7 @@ public class UserReader } } - protected static User<? extends Principal> parseUser(JSONObject userObject) + protected static User<Principal> parseUser(JSONObject userObject) throws ReaderException, JSONException { JSONObject userIDObject = userObject.getJSONObject("userID"); diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/json/UserRequestReader.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/json/UserRequestReader.java new file mode 100644 index 0000000000000000000000000000000000000000..4e0ed7a9d0095fa85fb07c6079c50b2b10dfb359 --- /dev/null +++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/json/UserRequestReader.java @@ -0,0 +1,168 @@ +/* + ************************************************************************ + ******************* 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.json; + +import ca.nrc.cadc.ac.ReaderException; +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserRequest; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.*; +import java.security.Principal; +import java.util.Scanner; + +public class UserRequestReader +{ + /** + * Construct a UserRequest from an XML String source. + * + * @param json String of the XML. + * @return UserRequest UserRequest. + * @throws IOException + */ + public static UserRequest<Principal> read(String json) + throws IOException + { + if (json == null) + { + throw new IllegalArgumentException("XML must not be null"); + } + else + { + try + { + return parseUserRequest(new JSONObject(json)); + } + catch (JSONException e) + { + String error = "Unable to parse JSON to User because " + + e.getMessage(); + throw new ReaderException(error, e); + } + } + } + + /** + * Construct a User from a InputStream. + * + * @param in InputStream. + * @return User User. + * @throws ReaderException + * @throws IOException + */ + public static UserRequest<Principal> read(InputStream in) + throws IOException + { + if (in == null) + { + throw new IOException("stream closed"); + } + + Scanner s = new Scanner(in).useDelimiter("\\A"); + String json = s.hasNext() ? s.next() : ""; + + return read(json); + } + + /** + * Construct a User from a Reader. + * + * @param reader Reader. + * @return User User. + * @throws ReaderException + * @throws IOException + */ + public static UserRequest<Principal> read(Reader reader) + throws IOException + { + if (reader == null) + { + throw new IllegalArgumentException("reader must not be null"); + } + + Scanner s = new Scanner(reader).useDelimiter("\\A"); + String json = s.hasNext() ? s.next() : ""; + + return read(json); + } + + + protected static UserRequest<Principal> parseUserRequest( + JSONObject userRequestObject) + throws ReaderException, JSONException + { + final User<Principal> user = + ca.nrc.cadc.ac.json.UserReader.parseUser( + userRequestObject.getJSONObject("user")); + + return new UserRequest<Principal>(user, userRequestObject. + getString("password")); + } +} diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserReader.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserReader.java index 9b9ad2bbed498a5f1ca9f6b362db2b48a21559ab..e9b957c29ed85fcc8133c781a2b8618e15650116 100755 --- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserReader.java +++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserReader.java @@ -96,8 +96,8 @@ public class UserReader * @throws java.io.IOException * @throws java.net.URISyntaxException */ - public static User<? extends Principal> read(String xml) - throws ReaderException, IOException, URISyntaxException + public static User<Principal> read(String xml) + throws IOException, URISyntaxException { if (xml == null) { @@ -111,12 +111,10 @@ public class UserReader * * @param in InputStream. * @return User User. - * @throws ReaderException * @throws java.io.IOException - * @throws java.net.URISyntaxException */ - public static User<? extends Principal> read(InputStream in) - throws ReaderException, IOException, URISyntaxException + public static User<Principal> read(InputStream in) + throws IOException { if (in == null) { @@ -142,8 +140,8 @@ public class UserReader * @throws ReaderException * @throws java.io.IOException */ - public static User<? extends Principal> read(Reader reader) - throws ReaderException, IOException + public static User<Principal> read(Reader reader) + throws IOException { if (reader == null) { @@ -168,7 +166,7 @@ public class UserReader return parseUser(root); } - protected static User<? extends Principal> parseUser(Element userElement) + protected static User<Principal> parseUser(Element userElement) throws ReaderException { // userID element of the User element diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestReader.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestReader.java index f7c0e8553ab0bc61f3b6ff8d6f5827d4bd717605..da30cafda3aa6e952fa5eec3682318f9543b5555 100644 --- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestReader.java +++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestReader.java @@ -78,7 +78,6 @@ import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.io.UnsupportedEncodingException; -import java.net.URISyntaxException; import java.security.Principal; import org.jdom2.Document; @@ -92,12 +91,10 @@ public class UserRequestReader * * @param xml String of the XML. * @return UserRequest UserRequest. - * @throws ReaderException * @throws java.io.IOException - * @throws java.net.URISyntaxException */ - public static UserRequest<? extends Principal> read(String xml) - throws ReaderException, IOException, URISyntaxException + public static UserRequest<Principal> read(String xml) + throws IOException { if (xml == null) { @@ -113,10 +110,9 @@ public class UserRequestReader * @return UserRequest UserRequest. * @throws ReaderException * @throws java.io.IOException - * @throws java.net.URISyntaxException */ - public static UserRequest<? extends Principal> read(InputStream in) - throws ReaderException, IOException, URISyntaxException + public static UserRequest<Principal> read(InputStream in) + throws IOException { if (in == null) { @@ -142,8 +138,8 @@ public class UserRequestReader * @throws ReaderException * @throws java.io.IOException */ - public static UserRequest<? extends Principal> read(Reader reader) - throws ReaderException, IOException + public static UserRequest<Principal> read(Reader reader) + throws IOException { if (reader == null) { @@ -168,7 +164,8 @@ public class UserRequestReader return parseUserRequest(root); } - protected static UserRequest parseUserRequest(Element userRequestElement) + protected static UserRequest<Principal> parseUserRequest( + Element userRequestElement) throws ReaderException { // user element of the UserRequest element @@ -178,7 +175,7 @@ public class UserRequestReader String error = "user element not found in userRequest element"; throw new ReaderException(error); } - User<? extends Principal> user = ca.nrc.cadc.ac.xml.UserReader.parseUser(userElement); + User<Principal> user = ca.nrc.cadc.ac.xml.UserReader.parseUser(userElement); // password element of the userRequest element Element passwordElement = userRequestElement.getChild("password"); @@ -189,9 +186,6 @@ public class UserRequestReader } String password = passwordElement.getText(); - UserRequest userRequest = new UserRequest(user, password); - - return userRequest; + return new UserRequest<Principal>(user, password); } - }