diff --git a/cadcAccessControl-Admin/build.xml b/cadcAccessControl-Admin/build.xml index 16291476f40028d842195c013998e9faa387d4c9..4486ba294d478ed652fbb5b566c0932a4e005bdc 100644 --- a/cadcAccessControl-Admin/build.xml +++ b/cadcAccessControl-Admin/build.xml @@ -161,16 +161,4 @@ <property name="testingJars" value="${jsonassert}:${junit}:${asm}:${cglib}:${easymock}:${objenesis}:${jdom2}:${json}:${cadcLog}"/> - <target name="int-test" depends="build,compile-test,setup-test"> - <echo message="Running test suite..."/> - <junit printsummary="yes" haltonfailure="yes" fork="yes"> - <classpath> - <pathelement path="${build}/class"/> - <pathelement path="${build}/test/class"/> - <pathelement path="${jars}:${testingJars}"/> - </classpath> - <test name="ca.nrc.cadc.ac.admin.integration.UserAdminIntTest"/> - <formatter type="plain" usefile="false"/> - </junit> - </target> </project> diff --git a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractCommand.java b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractCommand.java index e6966c3836ed8067bcc81daa14b8baccca6d6f2c..a5a32ed8aad8a4ff57f75352ee99b9f22e23bfa5 100644 --- a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractCommand.java +++ b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractCommand.java @@ -71,7 +71,6 @@ package ca.nrc.cadc.ac.admin; import java.io.PrintStream; import java.security.AccessControlException; -import java.security.Principal; import java.security.PrivilegedAction; import ca.nrc.cadc.ac.server.UserPersistence; @@ -88,12 +87,12 @@ public abstract class AbstractCommand implements PrivilegedAction<Object> protected PrintStream systemOut = System.out; protected PrintStream systemErr = System.err; - private UserPersistence<Principal> userPersistence; + private UserPersistence userPersistence; + - protected abstract void doRun() throws AccessControlException, TransientException; - + /** * Set the system out. * @param printStream The stream to write System.out to . @@ -102,7 +101,7 @@ public abstract class AbstractCommand implements PrivilegedAction<Object> { this.systemOut = printStream; } - + /** * Set the system err. * @param printStream The stream to write System.err to. @@ -111,36 +110,36 @@ public abstract class AbstractCommand implements PrivilegedAction<Object> { this.systemErr = printStream; } - + @Override - public Object run() + public Object run() { - try + try { this.doRun(); - } - catch (AccessControlException e) + } + catch (AccessControlException e) { this.systemErr.println("ERROR: " + e.getMessage()); e.printStackTrace(systemErr); - } - catch (TransientException e) + } + catch (TransientException e) { String message = "Internal Transient Error: " + e.getMessage(); this.systemErr.println("ERROR: " + message); e.printStackTrace(systemErr); } - + return null; } protected void setUserPersistence( - final UserPersistence<Principal> userPersistence) + final UserPersistence userPersistence) { this.userPersistence = userPersistence; } - public UserPersistence<Principal> getUserPersistence() + public UserPersistence getUserPersistence() { return userPersistence; } diff --git a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractListUsers.java b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractListUsers.java index 6372a0e5821ef100bc55a3394c345b87bf06f673..6cdbab61a354e8f500734b7ba8f5a4e6dc1a401a 100644 --- a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractListUsers.java +++ b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractListUsers.java @@ -70,14 +70,15 @@ package ca.nrc.cadc.ac.admin; import java.security.AccessControlException; -import java.security.Principal; import java.util.Collection; import java.util.Set; +import javax.security.auth.x500.X500Principal; + import org.apache.log4j.Logger; -import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; /** @@ -89,14 +90,14 @@ public abstract class AbstractListUsers extends AbstractCommand { private static final Logger log = Logger.getLogger(AbstractListUsers.class); - protected abstract Collection<User<Principal>> getUsers() + protected abstract Collection<User> getUsers() throws AccessControlException, TransientException; protected void doRun() throws AccessControlException, TransientException { - Collection<User<Principal>> users = this.getUsers(); + Collection<User> users = this.getUsers(); - for (User<Principal> user : users) + for (User user : users) { this.systemOut.println(getUserString(user)); } @@ -106,21 +107,36 @@ public abstract class AbstractListUsers extends AbstractCommand private String getUserString(User user) { - StringBuilder sb = new StringBuilder(user.getUserID().getName()); + StringBuilder sb = new StringBuilder(); + HttpPrincipal username = user.getHttpPrincipal(); + if (username != null) + { + sb.append(username.getName()); + } + else + { + Set<X500Principal> x500Principals = user.getIdentities(X500Principal.class); + if (!x500Principals.isEmpty()) + { + sb.append(x500Principals.iterator().next().getName()); + } + else + { + sb.append("Internal ID: " + user.getID().getURI()); + } + } - Set<PersonalDetails> detailSet = user.getDetails(PersonalDetails.class); - if (detailSet.size() > 0) + if (user.personalDetails != null) { sb.append(" ["); - PersonalDetails details = detailSet.iterator().next(); - sb.append(details.getFirstName()); + sb.append(user.personalDetails.getFirstName()); sb.append(" "); - sb.append(details.getLastName()); + sb.append(user.personalDetails.getLastName()); sb.append("]"); - if (details.institute != null) + if (user.personalDetails.institute != null) { sb.append(" ["); - sb.append(details.institute); + sb.append(user.personalDetails.institute); sb.append("]"); } } diff --git a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractUserCommand.java b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractUserCommand.java index ac5721e487361a32dd0fc90e84e97f01db87d559..105d66fc594c74c49f1388058cb6b6150110e927 100644 --- a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractUserCommand.java +++ b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/AbstractUserCommand.java @@ -75,7 +75,6 @@ import java.util.Set; import org.apache.log4j.Logger; -import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.auth.HttpPrincipal; @@ -86,12 +85,12 @@ import ca.nrc.cadc.net.TransientException; * @author yeunga * */ -public abstract class AbstractUserCommand extends AbstractCommand +public abstract class AbstractUserCommand extends AbstractCommand { private static final Logger log = Logger.getLogger(AbstractUserCommand.class); - + private HttpPrincipal principal; - protected abstract void execute() + protected abstract void execute() throws UserNotFoundException, AccessControlException, TransientException; /** @@ -102,26 +101,26 @@ public abstract class AbstractUserCommand extends AbstractCommand { this.principal = new HttpPrincipal(userID); } - + protected Principal getPrincipal() { return this.principal; } - + protected void doRun() throws AccessControlException, TransientException { - try + try { this.execute(); - } - catch (UserNotFoundException e1) + } + catch (UserNotFoundException e1) { String msg = "User " + this.getPrincipal().getName() + " was not found."; this.systemOut.println(msg); - } + } } - - protected void printUser(final User<Principal> user) + + protected void printUser(final User user) { if (user != null) { @@ -133,13 +132,12 @@ public abstract class AbstractUserCommand extends AbstractCommand { this.systemOut.println(p.toString()); } - + // print user's personal details this.systemOut.println(); - PersonalDetails personalDetails = user.getUserDetail(PersonalDetails.class); - if (personalDetails != null) + if (user.personalDetails != null) { - this.systemOut.println(personalDetails.toStringFormatted()); + this.systemOut.println(user.personalDetails.toStringFormatted()); } } } diff --git a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ApproveUser.java b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ApproveUser.java index c8270faae57ea4e3d7c2dc9257e80c08d1401efb..6f46a9f961b2d953b2e3f901e4b4ed9798143837 100644 --- a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ApproveUser.java +++ b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ApproveUser.java @@ -70,11 +70,9 @@ package ca.nrc.cadc.ac.admin; import java.security.AccessControlException; -import java.security.Principal; import java.util.Date; import java.util.IllegalFormatException; import java.util.Properties; -import java.util.Set; import javax.mail.Address; import javax.mail.Message; @@ -86,14 +84,12 @@ import javax.security.auth.x500.X500Principal; import org.apache.log4j.Logger; -import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.util.PropertiesReader; - /** * This class approves the specified pending user by moving the user * from a pending user to an active user in the LDAP server. @@ -115,69 +111,19 @@ public class ApproveUser extends AbstractUserCommand private String dn; - /** * Constructor * @param userID Id of the pending user to be approved - * @param dn of the pending user to be approved */ public ApproveUser(final String userID, final String dn) - { - super(userID); - this.dn = dn; - } - - - /** - * Constructor - * @param userID Id of the pending user to be approved - */ - public ApproveUser(final String userID) { super(userID); + this.dn = dn; } - protected void execute() throws AccessControlException, UserNotFoundException, TransientException { - User<Principal> user = null; - try - { - // Search the user in the pending tree - user = this.getUserPersistence().getPendingUser(this.getPrincipal()); - } - catch (Exception e) - { - log.info("User not found in userRequests"); - this.systemOut.println("User not found in userRequests. Impossible to approve it."); - this.systemOut.println("Check the validity of the provided uid."); - return; - } - log.debug("User found in userRequests"); - // If user DN is not provided by command line, search if it is available in UserRequests - if (dn == null || dn.isEmpty()) { - boolean foundDN = false; - for (Principal p : user.getIdentities()) - { - if (p instanceof X500Principal) - { - this.dn = p.getName(); - log.debug("User DN FOUND in pendingUser. userDN = " + dn); - foundDN = true; - break; - } - } - if(!foundDN) - { - log.debug("User DN NOT FOUND in UserRequests."); - this.systemOut.println("User DN not found in userRequests."); - this.systemOut.println("Use --dn option to provide a valid user DN"); - return; - } - - } - X500Principal dnPrincipal = null; try { @@ -192,16 +138,17 @@ public class ApproveUser extends AbstractUserCommand try { - this.getUserPersistence().approvePendingUser(this.getPrincipal()); + this.getUserPersistence().approveUserRequest(this.getPrincipal()); this.systemOut.println("User " + this.getPrincipal().getName() + " was approved successfully."); approved = true; } catch (UserNotFoundException e) { - this.systemOut.println("Could not find pending user " + this.getPrincipal()); + this.systemOut.println("Could not find userRequest " + this.getPrincipal()); + return; } - user = null; + User user = null; try { user = this.getUserPersistence().getUser(this.getPrincipal()); @@ -226,7 +173,7 @@ public class ApproveUser extends AbstractUserCommand } - private void emailUser(User<Principal> user) + private void emailUser(User user) { try { @@ -252,12 +199,10 @@ public class ApproveUser extends AbstractUserCommand return; } - Set<PersonalDetails> pds = user.getDetails(PersonalDetails.class); String recipient = null; - if (pds != null && !pds.isEmpty()) + if (user.personalDetails != null) { - PersonalDetails pd = pds.iterator().next(); - recipient = pd.email; + recipient = user.personalDetails.email; } if (recipient == null) { diff --git a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/CmdLineParser.java b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/CmdLineParser.java index 5411f1a56a7ba2568897e8243eeec6c01b5de109..40185149c2bafc61c4fe92adc08d84e945067e7b 100644 --- a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/CmdLineParser.java +++ b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/CmdLineParser.java @@ -187,13 +187,13 @@ public class CmdLineParser if (am.isSet("list")) { System.out.println("--list"); - this.command = new ListActiveUsers(); + this.command = new ListUsers(); count++; } if (am.isSet("list-pending")) { - this.command = new ListPendingUsers(); + this.command = new ListUserRequests(); count++; } @@ -231,7 +231,7 @@ public class CmdLineParser } else { - this.command = new ApproveUser(userID); + throw new UsageException("Missing parameter 'dn'"); } } diff --git a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/CommandRunner.java b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/CommandRunner.java index 21e28716d6e2b56aa12890900de0551d59710342..6c8943814e7fb68da0f5945fcf9ce4ef8887841d 100644 --- a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/CommandRunner.java +++ b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/CommandRunner.java @@ -92,11 +92,11 @@ public class CommandRunner { private final static Logger LOGGER = Logger.getLogger(CommandRunner.class); private final CmdLineParser commandLineParser; - private final UserPersistence<Principal> userPersistence; + private final UserPersistence userPersistence; public CommandRunner(final CmdLineParser commandLineParser, - final UserPersistence<Principal> userPersistence) + final UserPersistence userPersistence) { this.commandLineParser = commandLineParser; this.userPersistence = userPersistence; diff --git a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListPendingUsers.java b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListUserRequests.java similarity index 92% rename from cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListPendingUsers.java rename to cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListUserRequests.java index 117ef317f441fd5d4d32310981b998e89f6410f8..66f48174b29e87d54990a65fdc22c1509c024bd5 100644 --- a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListPendingUsers.java +++ b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListUserRequests.java @@ -70,7 +70,6 @@ package ca.nrc.cadc.ac.admin; import java.security.AccessControlException; -import java.security.Principal; import java.util.Collection; import org.apache.log4j.Logger; @@ -80,17 +79,17 @@ import ca.nrc.cadc.net.TransientException; /** * This class provides a list of all active or pending users in the LDAP server. - * The users' nsaccountlocked attribute is not set. + * The users' nsaccountlocked attribute is not set. * @author yeunga * */ -public class ListPendingUsers extends AbstractListUsers -{ - private static final Logger log = Logger.getLogger(ListPendingUsers.class); - - protected Collection<User<Principal>> getUsers() +public class ListUserRequests extends AbstractListUsers +{ + private static final Logger log = Logger.getLogger(ListUserRequests.class); + + protected Collection<User> getUsers() throws AccessControlException, TransientException { - return this.getUserPersistence().getPendingUsers(); + return this.getUserPersistence().getUserRequests(); } } diff --git a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListActiveUsers.java b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListUsers.java similarity index 95% rename from cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListActiveUsers.java rename to cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListUsers.java index 337c8a49071ea2a534e7f55dd1c88c30e96299c1..1256ad9af5a0a8f8e3d63356bddd808e06d7b790 100644 --- a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListActiveUsers.java +++ b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ListUsers.java @@ -70,7 +70,6 @@ package ca.nrc.cadc.ac.admin; import java.security.AccessControlException; -import java.security.Principal; import java.util.Collection; import org.apache.log4j.Logger; @@ -84,11 +83,11 @@ import ca.nrc.cadc.net.TransientException; * @author yeunga * */ -public class ListActiveUsers extends AbstractListUsers -{ - private static final Logger log = Logger.getLogger(ListActiveUsers.class); - - protected Collection<User<Principal>> getUsers() +public class ListUsers extends AbstractListUsers +{ + private static final Logger log = Logger.getLogger(ListUsers.class); + + protected Collection<User> getUsers() throws AccessControlException, TransientException { return this.getUserPersistence().getUsers(); diff --git a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/Main.java b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/Main.java index d8fdc3ff0e1e93c08ac7fdcd297f76610dbabee9..1bfe0de8879a4a7bab47527b8bf8117f46d609c8 100644 --- a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/Main.java +++ b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/Main.java @@ -70,7 +70,6 @@ package ca.nrc.cadc.ac.admin; import java.io.PrintStream; -import java.security.Principal; import java.security.cert.CertificateException; import org.apache.log4j.Logger; @@ -151,7 +150,7 @@ public class Main // Set the necessary JNDI system property for lookups. System.setProperty("java.naming.factory.initial", ContextFactoryImpl.class.getName()); - UserPersistence<Principal> userPersistence = new PluginFactory().createUserPersistence(); + UserPersistence userPersistence = new PluginFactory().createUserPersistence(); final CommandRunner runner = new CommandRunner(parser, userPersistence); runner.run(); diff --git a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/RejectUser.java b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/RejectUser.java index 77d97486c7ec21ea40a70cb9739290d315695295..4050de7b22186cc4fd0c06a7a70205a840d26d21 100644 --- a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/RejectUser.java +++ b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/RejectUser.java @@ -98,7 +98,7 @@ public class RejectUser extends AbstractUserCommand throws AccessControlException, UserNotFoundException, TransientException { // delete user from the pending tree - this.getUserPersistence().deletePendingUser(this.getPrincipal()); + this.getUserPersistence().deleteUserRequest(this.getPrincipal()); String msg = "User " + this.getPrincipal().getName() + " was rejected successfully."; this.systemOut.println(msg); } diff --git a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ViewUser.java b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ViewUser.java index f83408f9f54e2319a2c41592ecc2e92a3ca77c4d..6201ca876d905d73bd634ea381eedcdc93305052 100644 --- a/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ViewUser.java +++ b/cadcAccessControl-Admin/src/ca/nrc/cadc/ac/admin/ViewUser.java @@ -70,7 +70,6 @@ package ca.nrc.cadc.ac.admin; import java.security.AccessControlException; -import java.security.Principal; import org.apache.log4j.Logger; @@ -83,10 +82,10 @@ import ca.nrc.cadc.net.TransientException; * @author yeunga * */ -public class ViewUser extends AbstractUserCommand +public class ViewUser extends AbstractUserCommand { private static final Logger log = Logger.getLogger(ViewUser.class); - + /** * Constructor * @param userID Id of the user to provide details for @@ -96,22 +95,22 @@ public class ViewUser extends AbstractUserCommand super(userID); log.debug("view user: " + userID); } - - protected void execute() - throws AccessControlException, TransientException, UserNotFoundException + + protected void execute() + throws AccessControlException, TransientException, UserNotFoundException { - try + try { // Try the main tree first log.debug("principal: " + this.getPrincipal()); - User<Principal> user = this.getUserPersistence().getUser(this.getPrincipal()); + User user = this.getUserPersistence().getUser(this.getPrincipal()); this.printUser(user); - } - catch (UserNotFoundException e) + } + catch (UserNotFoundException e) { // Not in the main tree, try the pending tree - User<Principal> user = this.getUserPersistence().getPendingUser(this.getPrincipal()); + User user = this.getUserPersistence().getUserRequest(this.getPrincipal()); this.printUser(user); - } + } } } diff --git a/cadcAccessControl-Admin/test/LdapConfig.properties b/cadcAccessControl-Admin/test/LdapConfig.properties deleted file mode 100644 index 27f519ac7bb015646dcdabdf763c2a6ebcf8c447..0000000000000000000000000000000000000000 --- a/cadcAccessControl-Admin/test/LdapConfig.properties +++ /dev/null @@ -1,48 +0,0 @@ -############################################################### -# -# LDAP Connection and Pool Configuration -# -# -############################################################### - -# Read-only connection pool -readOnly.servers = proc5-03.cadc.dao.nrc.ca -readOnly.poolInitSize = 1 -readOnly.poolMaxSize = 2 -readOnly.poolPolicy = roundRobin -readOnly.maxWait = 30000 -readOnly.createIfNeeded = false - -# Read-write connection pool -readWrite.servers = proc5-03.cadc.dao.nrc.ca -readWrite.poolInitSize = 1 -readWrite.poolMaxSize = 2 -readWrite.poolPolicy = roundRobin -readWrite.maxWait = 30000 -readWrite.createIfNeeded = false - -# Unbound-Read-only connection pool -unboundReadOnly.servers = proc5-03.cadc.dao.nrc.ca -unboundReadOnly.poolInitSize = 1 -unboundReadOnly.poolMaxSize = 2 -unboundReadOnly.poolPolicy = roundRobin -unboundReadOnly.maxWait = 30000 -unboundReadOnly.createIfNeeded = false - -# server configuration -- applies to all servers -#dbrcHost = devLdap -#port = 636 -#proxyUser = uid=webproxy,ou=SpecialUsers,dc=canfar,dc=net -#usersDN = ou=Users,ou=ds,dc=canfar,dc=net -#userRequestsDN = ou=userRequests,ou=ds,dc=canfar,dc=net -#groupsDN = ou=Groups,ou=ds,dc=canfar,dc=net -#adminGroupsDN = ou=adminGroups,ou=ds,dc=canfar,dc=net - -# tree without aci's -dbrcHost = devLdap -port = 389 -proxyUser = uid=testproxy,ou=SpecialUsers,dc=testcanfar -usersDN = ou=Users,ou=ds,dc=testcanfar -userRequestsDN = ou=UserRequests,ou=ds,dc=testcanfar -groupsDN = ou=Groups,ou=ds,dc=testcanfar -adminGroupsDN = ou=adminGroups,ou=ds,dc=testcanfar \ No newline at end of file diff --git a/cadcAccessControl-Admin/test/src/ca/nrc/cadc/ac/admin/CmdLineParserTest.java b/cadcAccessControl-Admin/test/src/ca/nrc/cadc/ac/admin/CmdLineParserTest.java index 205817c8aaf761eaf6cb02fb69bd476c6cc192c0..21b4810171e45b1a3ed1fe251085e036e7cc12d6 100644 --- a/cadcAccessControl-Admin/test/src/ca/nrc/cadc/ac/admin/CmdLineParserTest.java +++ b/cadcAccessControl-Admin/test/src/ca/nrc/cadc/ac/admin/CmdLineParserTest.java @@ -223,7 +223,7 @@ public class CmdLineParserTest String[] dArgs = {"--list", "-d"}; CmdLineParser parser = new CmdLineParser(dArgs, sysOut, sysErr); Assert.assertEquals(Level.DEBUG, parser.getLogLevel()); - Assert.assertTrue(parser.getCommand() instanceof ListActiveUsers); + Assert.assertTrue(parser.getCommand() instanceof ListUsers); } catch (Exception e) { @@ -236,7 +236,7 @@ public class CmdLineParserTest String[] dArgs = {"--list-pending", "-d"}; CmdLineParser parser = new CmdLineParser(dArgs, sysOut, sysErr); Assert.assertEquals(Level.DEBUG, parser.getLogLevel()); - Assert.assertTrue(parser.getCommand() instanceof ListPendingUsers); + Assert.assertTrue(parser.getCommand() instanceof ListUserRequests); } catch (Exception e) { diff --git a/cadcAccessControl-Admin/test/src/ca/nrc/cadc/ac/admin/integration/UserAdminIntTest.java b/cadcAccessControl-Admin/test/src/ca/nrc/cadc/ac/admin/integration/UserAdminIntTest.java deleted file mode 100644 index 0fad739469226bf898a28ed643d766885ef82119..0000000000000000000000000000000000000000 --- a/cadcAccessControl-Admin/test/src/ca/nrc/cadc/ac/admin/integration/UserAdminIntTest.java +++ /dev/null @@ -1,410 +0,0 @@ -/* - ************************************************************************ - ******************* 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.admin.integration; - -import ca.nrc.cadc.ac.PersonalDetails; -import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.ac.UserAlreadyExistsException; -import ca.nrc.cadc.ac.UserNotFoundException; -import ca.nrc.cadc.ac.UserRequest; -import ca.nrc.cadc.ac.admin.ContextFactoryImpl; -import ca.nrc.cadc.ac.admin.Main; -import ca.nrc.cadc.ac.server.ldap.LdapConfig; -import ca.nrc.cadc.ac.server.ldap.LdapUserPersistence; -import ca.nrc.cadc.auth.DNPrincipal; -import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.net.TransientException; -import ca.nrc.cadc.util.Log4jInit; -import ca.nrc.cadc.util.PropertiesReader; -import ca.nrc.cadc.util.StringUtil; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; - -import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; -import java.io.*; -import java.security.Principal; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; - -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.*; - - -public class UserAdminIntTest -{ - private static final Logger log = Logger.getLogger(UserAdminIntTest.class); - - private final OutputStream output = new ByteArrayOutputStream(); - private final OutputStream error = new ByteArrayOutputStream(); - - static String testCert; - static LdapConfig config; - - @BeforeClass - public static void setUpClass() - throws Exception - { - Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); - - testCert = System.getProperty("user.dir") - + "/build/test/class/cadcauthtest1.pem"; - - config = LdapConfig.getLdapConfig(); - - System.setProperty(PropertiesReader.class.getName() + ".dir", "test"); - } - - @Test - public void listUsers() throws Exception - { - String[] args = new String[] { "--list" }; - - doTest(args); - - log.debug("number users found: " + output.toString()); - assertTrue("output is empty", StringUtil.hasText(output.toString())); - } - - @Test - public void listPendingUsers() throws Exception - { - String[] args = new String[] { "--list-pending" }; - - doTest(args); - - log.debug("number pending users found: " + output.toString()); - assertTrue("output is empty", StringUtil.hasText(output.toString())); - } - - @Test - public void viewUser() throws Exception - { - String userID = getUserID(); - boolean isPending = false; - addUser(userID, isPending); - - String[] args = new String[] { "--view=" + userID }; - - doTest(args); - log.debug("output: " + output); - - assertTrue("output is empty", StringUtil.hasText(output.toString())); - assertTrue("User ID not found in output.", - output.toString().contains(userID)); - } - - @Test - public void viewPendingUser() throws Exception - { - String userID = getUserID(); - boolean isPending = true; - addUser(userID, isPending); - - String[] args = new String[] { "--view=" + userID }; - - doTest(args); - log.debug("output: " + output); - - assertTrue("output is empty", StringUtil.hasText(output.toString())); - assertTrue("User ID not found in output.", - output.toString().contains(userID)); - } - - @Test - public void viewPendingUserNotFound() throws Exception - { - String userID = "foo_" + System.currentTimeMillis(); - - String[] args = new String[] { "--view=" + userID }; - - doTest(args); - final String outputMessage = output.toString(); - final String errorMessage = error.toString(); - log.debug("output: " + outputMessage); - - assertTrue(outputMessage.contains("not found")); - assertFalse("Should not have error (" + errorMessage + ")", - StringUtil.hasLength(errorMessage)); - } - - @Test - public void approvePendingUser() throws Exception - { - String userID = getUserID(); - boolean isPending = true; - addUser(userID, isPending); - - String[] args = new String[] { "--approve=" + userID }; - - doTest(args); - log.debug("output: " + output); - - assertTrue("output is empty", StringUtil.hasText(output.toString())); - assertTrue("User not approved.", - output.toString().contains("was approved")); - - User<Principal> deletedUser = getUser(userID, true, false); - User<Principal> approvedUser = getUser(userID, false, true); - } - - @Test - public void approvePendingUserNotFound() throws Exception - { - String userID = "foo_" + System.currentTimeMillis(); - - String[] args = new String[] { "--approve=" + userID }; - - doTest(args); - - final String outputMessage = output.toString(); - final String errorMessage = error.toString(); - log.debug("output: " + outputMessage); - - assertTrue(outputMessage.contains("not found")); - assertFalse("Should not have error (" + errorMessage + ")", - StringUtil.hasLength(errorMessage)); - } - - @Test - public void rejectPendingUser() throws Exception - { - String userID = getUserID(); - boolean isPending = true; - addUser(userID, isPending); - - String[] args = new String[] { "--reject=" + userID }; - - doTest(args); - - final String outputMessage = output.toString(); - final String errorMessage = error.toString(); - log.debug("output: " + outputMessage); - - assertTrue("Should contain was rejected.", - outputMessage.contains("was rejected")); - assertFalse("Should not have error (" + errorMessage + ")", - StringUtil.hasLength(errorMessage)); - - getUser(userID, isPending, false); - } - - @Test - public void rejectPendingUserNotFound() throws Exception - { - String userID = "foo_" + System.currentTimeMillis(); - - String[] args = new String[] { "--reject=" + userID }; - - doTest(args); - - final String outputMessage = output.toString(); - final String errorMessage = error.toString(); - log.debug("output: " + outputMessage); - - assertTrue(outputMessage.contains("not found")); - assertFalse("Should not have error (" + errorMessage + ")", - StringUtil.hasLength(errorMessage)); - } - - String getUserID() - { - return "CadcAdminIntTestUser-" + System.currentTimeMillis(); - } - - void doTest(String[] args) throws Exception - { - final String[] programArgs = new String[args.length + 1]; - System.arraycopy(args, 0, programArgs, 0, args.length); - programArgs[programArgs.length - 1] = "--cert=" + testCert; - - final Main testSubject = new Main(new PrintStream(output), - new PrintStream(error)); - testSubject.execute(programArgs); - } - - void addUser(final String username, final boolean isPending) - throws UserAlreadyExistsException, TransientException, - PrivilegedActionException - { - final HttpPrincipal userID = new HttpPrincipal(username); - - String dn = "uid=" + username + "," + config.getUsersDN(); - X500Principal x500Principal = new X500Principal(dn); - - final User<Principal> expected = new User<Principal>(userID); - expected.getIdentities().add(userID); - expected.getIdentities().add(x500Principal); - - expected.details.add(new PersonalDetails("foo", "bar")); - - final UserRequest<Principal> userRequest = - new UserRequest<Principal>(expected, "123456".toCharArray()); - - Subject subject = new Subject(); - subject.getPrincipals().add(userID); - subject.getPrincipals().add(getDNPrincipal(username, isPending)); - - PrivilegedExceptionAction<Object> action = - new PrivilegedExceptionAction<Object>() - { - public Object run() - throws Exception - { - try - { - final LdapUserPersistence<Principal> userDAO = getUserPersistence(); - if (isPending) - { - userDAO.addPendingUser(userRequest); - log.debug("added pending user: " + username); - } - else - { - userDAO.addUser(userRequest); - log.debug("added user: " + username); - } - return null; - } - catch (Exception e) - { - log.error("Exception adding user: " + e.getMessage()); - throw new Exception("Problems", e); - } - } - }; - - Subject.doAs(subject, action); - } - - User<Principal> getUser(final String username, final boolean isPending, - final boolean expectedFound) - throws PrivilegedActionException - { - final HttpPrincipal userID = new HttpPrincipal(username); - - Subject subject = new Subject(); - subject.getPrincipals().add(userID); - subject.getPrincipals().add(getDNPrincipal(username, isPending)); - - PrivilegedExceptionAction<User<Principal>> action = - new PrivilegedExceptionAction<User<Principal>>() - { - public User<Principal> run() - throws Exception - { - try - { - final LdapUserPersistence<Principal> userDAO = getUserPersistence(); - if (isPending) - { - return userDAO.getPendingUser(userID); - } - else - { - return userDAO.getUser(userID); - } - } - catch (UserNotFoundException e) - { - if (expectedFound) - { - throw e; - } - } - return null; - } - }; - - return Subject.doAs(subject, action); - } - - <T extends Principal> LdapUserPersistence<T> getUserPersistence() - { - System.setProperty("java.naming.factory.initial", ContextFactoryImpl.class.getName()); - return new LdapUserPersistence<T>(); - } - - DNPrincipal getDNPrincipal(final String username, final boolean isPending) - { - String entryDN = "uid=" + username + ","; - if (isPending) - { - entryDN = entryDN + config.getUserRequestsDN(); - } - else - { - entryDN = entryDN + config.getUsersDN(); - } - - return new DNPrincipal(entryDN); - } - -} diff --git a/cadcAccessControl-Server/build.xml b/cadcAccessControl-Server/build.xml index 07687e06a2d82d65627de11e61c74cd8f729a50c..413541216146fd16b1d2667761ff36d726e2c37d 100644 --- a/cadcAccessControl-Server/build.xml +++ b/cadcAccessControl-Server/build.xml @@ -138,7 +138,35 @@ <pathelement path="${jars}:${testingJars}"/> </classpath> <sysproperty key="ca.nrc.cadc.util.PropertiesReader.dir" value="test"/> + + <!--<test name="ca.nrc.cadc.ac.server.ldap.LdapConfigTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.ldap.LdapConnectionsTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.ldap.LdapDAOTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.ldap.LdapGroupDAOTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.ldap.LdapPersistenceTest" />--> <test name="ca.nrc.cadc.ac.server.ldap.LdapUserDAOTest" /> + + <!--<test name="ca.nrc.cadc.ac.server.web.groups.AddGroupMemberActionTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.groups.AddUserMemberActionTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.groups.DeleteGroupActionTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.groups.GetGroupNamesActionTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.groups.GroupActionFactoryTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.groups.RemoveGroupMemberActionTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.groups.RemoveUserMemberActionTest" />--> + + <!--<test name="ca.nrc.cadc.ac.server.web.users.GetUserActionTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.users.GetUserListActionTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.users.ModifyUserActionTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.users.UserActionFactoryTest" />--> + + <!--<test name="ca.nrc.cadc.ac.server.web.ModifyPasswordServletTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.ResetPasswordServletTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.UserLoginServletTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.UserServletTest" />--> + <!--<test name="ca.nrc.cadc.ac.server.web.WhoAmIServletTest" />--> + + <!--<test name="ca.nrc.cadc.ac.server.RequestValidatorTest" />--> + <formatter type="plain" usefile="false" /> </junit> </target> diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ACScopeValidator.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ACScopeValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..40f025ed7c22b075db9389ceab708dd106989c40 --- /dev/null +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ACScopeValidator.java @@ -0,0 +1,100 @@ +/* +************************************************************************ +******************* CANADIAN ASTRONOMY DATA CENTRE ******************* +************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** +* +* (c) 2009. (c) 2009. +* 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; + +import ca.nrc.cadc.auth.DelegationToken; +import ca.nrc.cadc.auth.InvalidDelegationTokenException; +import java.net.URI; + +/** + * A class to validate the scope of a delegation token for access control. + * The scope of a delegation token is composed of the service endpoint + * and the action allowed with the service endpoint. Both the service endpoint + * and the action are validated. + * @author yeunga + */ +public class ACScopeValidator extends DelegationToken.ScopeValidator +{ + public static final String RESET_PASSWORD_SCOPE = "/resetPassword"; + + public ACScopeValidator() { } + + @Override + public void verifyScope(URI scope, String requestURI) + throws InvalidDelegationTokenException + { + if (!requestURI.endsWith(RESET_PASSWORD_SCOPE) + && !scope.toASCIIString().equals(RESET_PASSWORD_SCOPE)) + { + throw new InvalidDelegationTokenException("invalid scope: " + + scope); + } + } +} diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java index 3de5f42753b1c62ab51b901bb79736a1e4df5c9a..ce1839d2ed007059fa20df47b232c6e9eb68ffa0 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java @@ -69,7 +69,6 @@ package ca.nrc.cadc.ac.server; import java.security.AccessControlException; -import java.security.Principal; import java.util.Collection; import ca.nrc.cadc.ac.Group; @@ -79,7 +78,7 @@ import ca.nrc.cadc.ac.Role; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.net.TransientException; -public interface GroupPersistence<T extends Principal> +public interface GroupPersistence { /** * Call if this object is to be shut down. diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/PluginFactory.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/PluginFactory.java index f2e0cbce375a67f85392568f509a7dac6f11f625..582d770f06ff8c3f8036ca2009d653d4698c69ba 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/PluginFactory.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/PluginFactory.java @@ -68,18 +68,14 @@ */ package ca.nrc.cadc.ac.server; -import ca.nrc.cadc.ac.server.ldap.LdapGroupPersistence; -import ca.nrc.cadc.ac.server.ldap.LdapUserPersistence; - -import java.lang.reflect.Constructor; import java.net.URL; -import java.security.AccessControlException; import java.security.Principal; import java.util.Properties; -import java.util.Set; + import org.apache.log4j.Logger; -import com.unboundid.ldap.sdk.LDAPException; +import ca.nrc.cadc.ac.server.ldap.LdapGroupPersistence; +import ca.nrc.cadc.ac.server.ldap.LdapUserPersistence; public class PluginFactory { @@ -118,20 +114,20 @@ public class PluginFactory } @SuppressWarnings("unchecked") - public <T extends Principal> GroupPersistence<T> createGroupPersistence() + public <T extends Principal> GroupPersistence createGroupPersistence() { String name = GroupPersistence.class.getName(); String cname = config.getProperty(name); if (cname == null) { - return new LdapGroupPersistence<T>(); + return new LdapGroupPersistence(); } else { try { Class<?> c = Class.forName(cname); - return (GroupPersistence<T>) c.newInstance(); + return (GroupPersistence) c.newInstance(); } catch (Exception ex) { @@ -141,14 +137,14 @@ public class PluginFactory } @SuppressWarnings("unchecked") - public <T extends Principal> UserPersistence<T> createUserPersistence() + public <T extends Principal> UserPersistence createUserPersistence() { String name = UserPersistence.class.getName(); String cname = config.getProperty(name); if (cname == null) { - return new LdapUserPersistence<T>(); + return new LdapUserPersistence(); } else { diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java index 876ce4538b5a1d10d2d6e62d0df7e51bd6a23de9..ede2cd250f4aaf0a6839cd6b84f0b22ad6f67a53 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java @@ -68,6 +68,10 @@ */ package ca.nrc.cadc.ac.server; +import java.security.AccessControlException; +import java.security.Principal; +import java.util.Collection; + import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserAlreadyExistsException; import ca.nrc.cadc.ac.UserNotFoundException; @@ -75,11 +79,7 @@ import ca.nrc.cadc.ac.UserRequest; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; -import java.security.AccessControlException; -import java.security.Principal; -import java.util.Collection; - -public interface UserPersistence<T extends Principal> +public interface UserPersistence { /** @@ -88,15 +88,15 @@ public interface UserPersistence<T extends Principal> void destroy(); /** - * Add the user to the active users tree. + * Add the user to the users tree. * - * @param user The user request to put into the active users tree. + * @param user The user request to put into the users tree. * * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. * @throws ca.nrc.cadc.ac.UserAlreadyExistsException */ - void addUser(UserRequest<T> user) + void addUser(User user) throws TransientException, AccessControlException, UserAlreadyExistsException; @@ -109,7 +109,7 @@ public interface UserPersistence<T extends Principal> * @throws AccessControlException If the operation is not permitted. * @throws ca.nrc.cadc.ac.UserAlreadyExistsException */ - void addPendingUser(UserRequest<T> user) + void addUserRequest(UserRequest user) throws TransientException, AccessControlException, UserAlreadyExistsException; @@ -124,29 +124,45 @@ public interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - User<T> getUser(T userID) + User getUser(Principal userID) throws UserNotFoundException, TransientException, AccessControlException; /** - * Get the user specified by userID whose account is pending approval. + * Get the user specified by email address exists in the active users tree. * - * @param userID The userID. + * @param emailAddress The user's email address. * * @return User instance. * * @throws UserNotFoundException when the user is not found. + * @throws UserAlreadyExistsException A user with the email address already exists * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - User<T> getPendingUser(T userID) + User getUserByEmailAddress(String emailAddress) + throws UserNotFoundException, UserAlreadyExistsException, + TransientException, AccessControlException; + + /** + * Get the user with the specified Principal whose account is pending approval. + * + * @param userID A Principal of the 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. + */ + User getUserRequest(Principal userID) throws UserNotFoundException, TransientException, AccessControlException; /** - * Get the user specified by userID with all of the users identities. + * Get the user with the specified Principal with all of the users identities. * - * @param userID The userID. + * @param userID A Principal of the User. * * @return User instance. * @@ -154,7 +170,7 @@ public interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - User<T> getAugmentedUser(T userID) + User getAugmentedUser(Principal userID) throws UserNotFoundException, TransientException, AccessControlException; @@ -165,7 +181,7 @@ public interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - Collection<User<Principal>> getUsers() + Collection<User> getUsers() throws TransientException, AccessControlException; /** @@ -175,14 +191,14 @@ public interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - Collection<User<Principal>> getPendingUsers() + Collection<User> getUserRequests() throws TransientException, AccessControlException; /** - * Move the pending user specified by userID from the + * Move the pending user with the specified Principal from the * pending users tree to the active users tree. * - * @param userID The userID. + * @param userID A Principal of the User. * * @return User instance. * @@ -190,12 +206,12 @@ public interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - User<T> approvePendingUser(T userID) + User approveUserRequest(Principal userID) throws UserNotFoundException, TransientException, AccessControlException; /** - * Update the user specified by userID in the active users tree. + * Update the user with the specified Principal in the active users tree. * * @param user The user instance to modify. * @@ -205,33 +221,46 @@ public interface UserPersistence<T extends Principal> * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - User<T> modifyUser(User<T> user) + User modifyUser(User user) throws UserNotFoundException, TransientException, AccessControlException; /** - * Delete the user specified by userID from the active users tree. + * Delete the user with the specified Principal from the active users tree. * - * @param userID The userID. + * @param userID A Principal of the User. * * @throws UserNotFoundException when the user is not found. * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - void deleteUser(T userID) + void deleteUser(Principal userID) throws UserNotFoundException, TransientException, AccessControlException; /** - * Delete the user specified by userID from the pending users tree. + * Deactivate the user with the specified Principal from the active users tree. * - * @param userID The userID. + * @param userID A Principal of the User. + * + * @throws UserNotFoundException when the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + void deactivateUser(Principal userID) + throws UserNotFoundException, TransientException, + AccessControlException; + + /** + * Delete the user with the specified Principal from the pending users tree. + * + * @param userID A Principal of the User. * * @throws UserNotFoundException when the user is not found. * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - void deletePendingUser(T userID) + void deleteUserRequest(Principal userID) throws UserNotFoundException, TransientException, AccessControlException; @@ -264,4 +293,16 @@ public interface UserPersistence<T extends Principal> void setPassword(HttpPrincipal userID, String oldPassword, String newPassword) throws UserNotFoundException, TransientException, AccessControlException; + /** + * Reset a user's password. The given user and authenticating user must match. + * + * @param userID + * @param newPassword new password. + * @throws UserNotFoundException If the given user does not exist. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + void resetPassword(HttpPrincipal userID, String newPassword) + throws UserNotFoundException, TransientException, AccessControlException; + } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConfig.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConfig.java index 1cd4d5205bff0bc8db1797f2564be840d99712e4..055cfbd574da58d478751d615c920f1f4ef41899 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConfig.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConfig.java @@ -115,8 +115,15 @@ public class LdapConfig public enum PoolPolicy { roundRobin, - fewestConnections; - }; + fewestConnections + } + + public enum SystemState + { + ONLINE, + READONLY, + OFFLINE + } public class LdapPool { @@ -210,6 +217,7 @@ public class LdapConfig private String proxyUserDN; private String proxyPasswd; private String dbrcHost; + private SystemState systemState; public String getProxyUserDN() { @@ -251,6 +259,8 @@ public class LdapConfig ldapConfig.groupsDN = getProperty(pr, LDAP_GROUPS_DN); ldapConfig.adminGroupsDN = getProperty(pr, LDAP_ADMIN_GROUPS_DN); + ldapConfig.systemState = getSystemState(ldapConfig); + try { DBConfig dbConfig = new DBConfig(); @@ -304,6 +314,27 @@ public class LdapConfig return Arrays.asList(props); } + private static SystemState getSystemState(LdapConfig ldapConfig) + { + if (ldapConfig.getReadOnlyPool().getMaxSize() == 0) + { + return SystemState.OFFLINE; + } + + if (ldapConfig.getUnboundReadOnlyPool().getMaxSize() == 0) + { + return SystemState.OFFLINE; + } + + if (ldapConfig.getReadWritePool().getMaxSize() == 0) + { + return SystemState.READONLY; + } + + return SystemState.ONLINE; + } + + @Override public boolean equals(Object other) { @@ -409,6 +440,17 @@ public class LdapConfig return this.proxyPasswd; } + /** + * Check if in read-only or offline mode. + * + * A read max connection size of zero implies offline mode. + * A read-wrtie max connection size of zero implies read-only mode. + */ + public SystemState getSystemState() + { + return systemState; + } + public String toString() { StringBuilder sb = new StringBuilder(); @@ -421,4 +463,5 @@ public class LdapConfig return sb.toString(); } + } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConnectionPool.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConnectionPool.java index ea65ec8f17f8d5e2d4cb7a6176e4d7a6af478948..118bb1bebd2d3457969fa5ebb86e1178961c6feb 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConnectionPool.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConnectionPool.java @@ -73,18 +73,16 @@ import org.apache.log4j.Logger; import ca.nrc.cadc.ac.server.ldap.LdapConfig.LdapPool; import ca.nrc.cadc.ac.server.ldap.LdapConfig.PoolPolicy; +import ca.nrc.cadc.ac.server.ldap.LdapConfig.SystemState; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.profiler.Profiler; import com.unboundid.ldap.sdk.FewestConnectionsServerSet; -import com.unboundid.ldap.sdk.Filter; import com.unboundid.ldap.sdk.LDAPConnection; import com.unboundid.ldap.sdk.LDAPConnectionOptions; import com.unboundid.ldap.sdk.LDAPConnectionPool; import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.RoundRobinServerSet; -import com.unboundid.ldap.sdk.SearchRequest; -import com.unboundid.ldap.sdk.SearchScope; import com.unboundid.ldap.sdk.ServerSet; import com.unboundid.ldap.sdk.SimpleBindRequest; @@ -100,15 +98,15 @@ public class LdapConnectionPool { private static final Logger logger = Logger.getLogger(LdapConnectionPool.class); - Profiler profiler = new Profiler(LdapConnectionPool.class); - protected LdapConfig currentConfig; private String poolName; private LDAPConnectionPool pool; private Object poolMonitor = new Object(); private LDAPConnectionOptions connectionOptions; + private boolean readOnly; + private SystemState systemState; - public LdapConnectionPool(LdapConfig config, LdapPool poolConfig, String poolName, boolean boundPool) + public LdapConnectionPool(LdapConfig config, LdapPool poolConfig, String poolName, boolean boundPool, boolean readOnly) { if (config == null) throw new IllegalArgumentException("config required"); @@ -122,38 +120,73 @@ public class LdapConnectionPool connectionOptions.setAutoReconnect(true); currentConfig = config; this.poolName = poolName; - synchronized (poolMonitor) + this.readOnly = readOnly; + + systemState = config.getSystemState(); + logger.debug("Construct pool: " + poolName + ". system state: " + systemState); + if (SystemState.ONLINE.equals(systemState) || (SystemState.READONLY.equals(systemState) && readOnly)) { - if (!boundPool) - pool = createPool(config, poolConfig, poolName, null, null); - else - pool = createPool(config, poolConfig, poolName, config.getAdminUserDN(), config.getAdminPasswd()); - logger.debug(poolName + " statistics after create:\n" + pool.getConnectionPoolStatistics()); - profiler.checkpoint("Create read only pool."); + Profiler profiler = new Profiler(LdapConnectionPool.class); + synchronized (poolMonitor) + { + if (!boundPool) + pool = createPool(config, poolConfig, poolName, null, null); + else + pool = createPool(config, poolConfig, poolName, config.getAdminUserDN(), config.getAdminPasswd()); + + if (pool != null) + { + logger.debug(poolName + " statistics after create:\n" + pool.getConnectionPoolStatistics()); + profiler.checkpoint("Create read only pool."); + } + } + } + else + { + logger.debug("Not creating pool " + poolName + " because system state is " + systemState); } } public LDAPConnection getConnection() throws TransientException { + + logger.debug("Get connection: " + poolName + ". system state: " + systemState); + if (SystemState.OFFLINE.equals(systemState)) + { + throw new TransientException("The system is down for maintenance.", 600); + } + + if (SystemState.READONLY.equals(systemState)) + { + if (!readOnly) + { + throw new TransientException("The system is in read-only mode.", 600); + } + } + try { + Profiler profiler = new Profiler(LdapConnectionPool.class); LDAPConnection conn = null; synchronized (poolMonitor) { conn = pool.getConnection(); - profiler.checkpoint("pool.getConnection"); // BM: This query to the base dn (starting at dc=) has the // effect of clearing any proxied authorization state associated // with the receiving ldap server connection. Without this in // place, proxied authorization information is sometimes ignored. - logger.debug("Testing connection"); - int dcIndex = currentConfig.getGroupsDN().indexOf("dc="); - String dcDN = currentConfig.getGroupsDN().substring(dcIndex); - Filter filter = Filter.createEqualityFilter("dc", "*"); - SearchRequest searchRequest = new SearchRequest(dcDN, SearchScope.BASE, filter, new String[] {"entrydn"}); - conn.search(searchRequest); - profiler.checkpoint("pool.initConnection"); +// logger.debug("Testing connection"); +// int index = currentConfig.getGroupsDN().indexOf(','); +// String rdn = currentConfig.getGroupsDN().substring(0, index); +// Filter filter = Filter.create("(" + rdn + ")"); +// +// index = rdn.indexOf('='); +// String attribute = rdn.substring(0, index); +// +// SearchRequest searchRequest = new SearchRequest(currentConfig.getGroupsDN(), SearchScope.BASE, filter, new String[] {attribute}); +// conn.search(searchRequest); +// profiler.checkpoint("pool.initConnection"); } logger.debug(poolName + " pool statistics after borrow:\n" + pool.getConnectionPoolStatistics()); profiler.checkpoint("get " + poolName + " only connection"); @@ -169,8 +202,13 @@ public class LdapConnectionPool public void releaseConnection(LDAPConnection conn) { - pool.releaseConnection(conn); - logger.debug(poolName + " pool statistics after release:\n" + pool.getConnectionPoolStatistics()); + if (pool != null) + { + Profiler profiler = new Profiler(LdapConnectionPool.class); + pool.releaseConnection(conn); + profiler.checkpoint("pool.releaseConnection"); + logger.debug(poolName + " pool statistics after release:\n" + pool.getConnectionPoolStatistics()); + } } public LdapConfig getCurrentConfig() @@ -180,9 +218,13 @@ public class LdapConnectionPool public void shutdown() { - logger.debug("Closing pool..."); - pool.close(); - profiler.checkpoint("Pool closed."); + if (pool != null) + { + logger.debug("Closing pool..."); + Profiler profiler = new Profiler(LdapConnectionPool.class); + pool.close(); + profiler.checkpoint("pool.shutdown"); + } } public String getName() @@ -191,7 +233,6 @@ public class LdapConnectionPool } private LDAPConnectionPool createPool(LdapConfig config, LdapPool poolConfig, String poolName, String bindID, String bindPW) - { try { @@ -244,5 +285,4 @@ public class LdapConnectionPool } } - } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConnections.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConnections.java index 0884176f27d2ad55d384f50b25b575081853746d..bef5ff93bfdcc554d55b72f272792c83226d6d0c 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConnections.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConnections.java @@ -91,8 +91,6 @@ class LdapConnections { private final static Logger log = Logger.getLogger(LdapConnections.class); - Profiler profiler = new Profiler(LdapConnections.class); - private LdapPersistence persistence; private LdapConfig config; @@ -134,6 +132,7 @@ class LdapConnections if (autoConfigReadOnlyConn == null) { log.debug("Getting new auto config read only connection."); + Profiler profiler = new Profiler(LdapConnections.class); autoConfigReadOnlyConn = readOnlyPool.getConnection(); profiler.checkpoint("Get read only connection"); } @@ -147,7 +146,7 @@ class LdapConnections { if (readOnlyPool == null) { - readOnlyPool = new LdapConnectionPool(config, config.getReadOnlyPool(), LdapPersistence.POOL_READONLY, true); + readOnlyPool = new LdapConnectionPool(config, config.getReadOnlyPool(), LdapPersistence.POOL_READONLY, true, true); } if (manualConfigReadOnlyConn == null) { @@ -173,6 +172,7 @@ class LdapConnections if (autoConfigReadWriteConn == null) { log.debug("Getting new auto config read write connection."); + Profiler profiler = new Profiler(LdapConnections.class); autoConfigReadWriteConn = readWritePool.getConnection(); profiler.checkpoint("Get read write connection"); } @@ -186,7 +186,7 @@ class LdapConnections { if (readWritePool == null) { - readWritePool = new LdapConnectionPool(config, config.getReadWritePool(), LdapPersistence.POOL_READWRITE, true); + readWritePool = new LdapConnectionPool(config, config.getReadWritePool(), LdapPersistence.POOL_READWRITE, true, false); } if (manualConfigReadWriteConn == null) { @@ -212,6 +212,7 @@ class LdapConnections if (autoConfigUnboundReadOnlyConn == null) { log.debug("Getting new auto config unbound read only connection."); + Profiler profiler = new Profiler(LdapConnections.class); autoConfigUnboundReadOnlyConn = unboundReadOnlyPool.getConnection(); profiler.checkpoint("Get read write connection"); } @@ -225,7 +226,7 @@ class LdapConnections { if (unboundReadOnlyPool == null) { - unboundReadOnlyPool = new LdapConnectionPool(config, config.getUnboundReadOnlyPool(), LdapPersistence.POOL_UNBOUNDREADONLY, false); + unboundReadOnlyPool = new LdapConnectionPool(config, config.getUnboundReadOnlyPool(), LdapPersistence.POOL_UNBOUNDREADONLY, false, true); } if (manualConfigUnboundReadOnlyConn == null) { @@ -242,6 +243,7 @@ class LdapConnections void releaseConnections() { + Profiler profiler = new Profiler(LdapConnections.class); if (persistence != null) { if (autoConfigReadOnlyConn != null) @@ -317,4 +319,5 @@ class LdapConnections return config; } + } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java index 49a83c207a75fa16b0fd4c35cac540a4d9c91f7c..35a06d069e9e32b550e2fcdfb45433dab6554363 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java @@ -68,30 +68,17 @@ */ package ca.nrc.cadc.ac.server.ldap; -import ca.nrc.cadc.auth.DNPrincipal; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.profiler.Profiler; - -import com.unboundid.ldap.sdk.BindRequest; -import com.unboundid.ldap.sdk.BindResult; import com.unboundid.ldap.sdk.DN; import com.unboundid.ldap.sdk.LDAPConnection; -import com.unboundid.ldap.sdk.LDAPConnectionPool; -import com.unboundid.ldap.sdk.LDAPException; -import com.unboundid.ldap.sdk.LDAPInterface; import com.unboundid.ldap.sdk.ResultCode; -import com.unboundid.ldap.sdk.SimpleBindRequest; - import org.apache.log4j.Logger; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; -import javax.security.auth.Subject; import java.security.AccessControlException; -import java.security.AccessController; import java.security.GeneralSecurityException; -import java.security.Principal; -import java.util.Set; public abstract class LdapDAO @@ -103,8 +90,6 @@ public abstract class LdapDAO DN subjDN = null; - private Profiler profiler = new Profiler(LdapDAO.class); - public LdapDAO(LdapConnections connections) { this.connections = connections; @@ -192,8 +177,8 @@ public abstract class LdapDAO if (config.isSecure()) { - socketFactory = createSSLSocketFactory(); Profiler profiler = new Profiler(LdapDAO.class); + socketFactory = createSSLSocketFactory(); profiler.checkpoint("createSSLSocketFactory"); } else diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java index 0afd857e436b4ab2bb2231a136c040a1d68b33d1..30897950e64ffc64411b1dee095d79cfe513af5d 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java @@ -68,8 +68,8 @@ */ package ca.nrc.cadc.ac.server.ldap; +import java.lang.reflect.Field; import java.security.AccessControlException; -import java.security.Principal; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -77,20 +77,15 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; -import javax.security.auth.x500.X500Principal; - import org.apache.log4j.Logger; import ca.nrc.cadc.ac.ActivatedGroup; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupAlreadyExistsException; import ca.nrc.cadc.ac.GroupNotFoundException; -import ca.nrc.cadc.ac.Role; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; -import ca.nrc.cadc.ac.client.GroupMemberships; import ca.nrc.cadc.ac.server.GroupDetailSelector; -import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.DNPrincipal; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.profiler.Profiler; @@ -114,37 +109,44 @@ import com.unboundid.ldap.sdk.SearchResultEntry; import com.unboundid.ldap.sdk.SearchResultListener; import com.unboundid.ldap.sdk.SearchResultReference; import com.unboundid.ldap.sdk.SearchScope; -import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl; -import java.security.AccessController; -import javax.security.auth.Subject; -public class LdapGroupDAO<T extends Principal> extends LdapDAO +public class LdapGroupDAO extends LdapDAO { private static final Logger logger = Logger.getLogger(LdapGroupDAO.class); + // LDAP Group attributes + protected static final String LDAP_CN = "cn"; + protected static final String LDAP_DESCRIPTION = "description"; + protected static final String LDAP_ENTRYDN = "entrydn"; + protected static final String LDAP_GROUP_OF_UNIQUE_NAMES = "groupofuniquenames"; + protected static final String LDAP_INET_USER = "inetuser"; + protected static final String LDAP_MODIFY_TIMESTAMP = "modifytimestamp"; + protected static final String LDAP_NSACCOUNTLOCK = "nsaccountlock"; + protected static final String LDAP_OBJECT_CLASS = "objectClass"; + protected static final String LDAP_OWNER = "owner"; + protected static final String LDAP_UNIQUE_MEMBER = "uniquemember"; + private static final String[] PUB_GROUP_ATTRS = new String[] { - "entrydn", "cn" + LDAP_ENTRYDN, LDAP_CN }; private static final String[] GROUP_ATTRS = new String[] { - "entrydn", "cn", "nsaccountlock", "owner", - "modifytimestamp", "description" + LDAP_ENTRYDN, LDAP_CN, LDAP_NSACCOUNTLOCK, LDAP_OWNER, + LDAP_MODIFY_TIMESTAMP, LDAP_DESCRIPTION }; private static final String[] GROUP_AND_MEMBER_ATTRS = new String[] { - "entrydn", "cn", "nsaccountlock", "owner", - "modifytimestamp", "description", "uniquemember" + LDAP_ENTRYDN, LDAP_CN, LDAP_NSACCOUNTLOCK, LDAP_OWNER, + LDAP_MODIFY_TIMESTAMP, LDAP_DESCRIPTION, LDAP_UNIQUE_MEMBER }; - private final Profiler profiler = new Profiler(LdapGroupDAO.class); - - private LdapUserDAO<T> userDAO; + private LdapUserDAO userDAO; // this gets filled by the LdapgroupPersistence GroupDetailSelector searchDetailSelector; - public LdapGroupDAO(LdapConnections connections, LdapUserDAO<T> userPersist) + public LdapGroupDAO(LdapConnections connections, LdapUserDAO userPersist) { super(connections); if (userPersist == null) @@ -177,13 +179,6 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO "Support for groups properties not available"); } - // BM: Changed so that the group owner is set to be the - // user in the subject - //if (!isCreatorOwner(group.getOwner())) - //{ - // throw new AccessControlException("Group owner must be creator"); - //} - try { Set<DNPrincipal> ds = group.getOwner().getIdentities(DNPrincipal.class); @@ -191,14 +186,13 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO throw new RuntimeException("BUG: User does not have an internal DNPrincipal"); DNPrincipal dnp = ds.iterator().next(); DN ownerDN = new DN(dnp.getName()); - + if (reactivateGroup(group)) { return; } else { - // add group to groups tree LDAPResult result = addGroup(getGroupDN(group.getID()), group.getID(), ownerDN, @@ -214,7 +208,6 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO group.getUserAdmins(), group.getGroupAdmins()); LdapDAO.checkLdapResult(result.getResultCode()); - } } catch (LDAPException e) @@ -227,27 +220,26 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO private LDAPResult addGroup(final DN groupDN, final String groupID, final DN ownerDN, final String description, - final Set<User<? extends Principal>> users, + final Set<User> users, final Set<Group> groups) throws UserNotFoundException, LDAPException, TransientException, AccessControlException, GroupNotFoundException { // add new group List<Attribute> attributes = new ArrayList<Attribute>(); - Attribute ownerAttribute = - new Attribute("owner", ownerDN.toNormalizedString()); + Attribute ownerAttribute = new Attribute(LDAP_OWNER, ownerDN.toNormalizedString()); attributes.add(ownerAttribute); - attributes.add(new Attribute("objectClass", "groupofuniquenames")); - attributes.add(new Attribute("objectClass", "inetUser")); - attributes.add(new Attribute("cn", groupID)); + attributes.add(new Attribute(LDAP_OBJECT_CLASS, LDAP_GROUP_OF_UNIQUE_NAMES)); + attributes.add(new Attribute(LDAP_OBJECT_CLASS, LDAP_INET_USER)); + attributes.add(new Attribute(LDAP_CN, groupID)); if (StringUtil.hasText(description)) { - attributes.add(new Attribute("description", description)); + attributes.add(new Attribute(LDAP_DESCRIPTION, description)); } List<String> members = new ArrayList<String>(); - for (User<? extends Principal> userMember : users) + for (User userMember : users) { DN memberDN = this.userDAO.getUserDN(userMember); members.add(memberDN.toNormalizedString()); @@ -264,16 +256,12 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } if (!members.isEmpty()) { - attributes.add(new Attribute("uniquemember", - (String[]) members - .toArray(new String[members - .size()]))); + attributes.add( + new Attribute(LDAP_UNIQUE_MEMBER, + (String[]) members.toArray(new String[members.size()]))); } AddRequest addRequest = new AddRequest(groupDN, attributes); - //addRequest.addControl( - // new ProxiedAuthorizationV2RequestControl( - // "dn:" + getSubjectDN().toNormalizedString())); logger.debug("addGroup: " + groupDN); return getReadWriteConnection().add(addRequest); @@ -298,27 +286,22 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO try { // check group name exists - Filter filter = Filter.createEqualityFilter("cn", group.getID()); + Filter filter = Filter.createEqualityFilter(LDAP_CN, group.getID()); DN groupDN = getGroupDN(group.getID()); SearchRequest searchRequest = - new SearchRequest(groupDN.toNormalizedString(), SearchScope.BASE, filter, - new String[]{"nsaccountlock"}); + new SearchRequest(groupDN.toNormalizedString(), SearchScope.BASE, + filter, new String[]{LDAP_NSACCOUNTLOCK}); - //searchRequest.addControl( - // new ProxiedAuthorizationV2RequestControl("dn:" + - // getSubjectDN() - // .toNormalizedString())); - - SearchResultEntry searchResult = getReadWriteConnection() - .searchForEntry(searchRequest); + SearchResultEntry searchResult = + getReadWriteConnection().searchForEntry(searchRequest); if (searchResult == null) { return false; } - if (searchResult.getAttributeValue("nsaccountlock") == null) + if (searchResult.getAttributeValue(LDAP_NSACCOUNTLOCK) == null) { throw new GroupAlreadyExistsException("Group already exists " + group.getID()); } @@ -356,7 +339,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO try { Filter filter = Filter - .createNOTFilter(Filter.createPresenceFilter("nsaccountlock")); + .createNOTFilter(Filter.createPresenceFilter(LDAP_NSACCOUNTLOCK)); filter = Filter.createANDFilter(filter, Filter.create("(cn=*)")); final List<String> groupNames = new LinkedList<String>(); @@ -367,7 +350,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO public void searchEntryReturned(SearchResultEntry sre) { - String gname = sre.getAttributeValue("cn"); + String gname = sre.getAttributeValue(LDAP_CN); groupNames.add(gname); long t2 = System.currentTimeMillis(); @@ -379,23 +362,22 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } if ((groupNames.size() % 100) == 0) { - - logger.debug("found: " + groupNames - .size() + " " + dt + "ms"); + logger.debug("found: " + groupNames.size() + + " " + dt + "ms"); t1 = t2; } } public void searchReferenceReturned(SearchResultReference srr) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } - }, config - .getGroupsDN(), SearchScope.ONE, filter, PUB_GROUP_ATTRS); + }, config.getGroupsDN(), SearchScope.ONE, filter, PUB_GROUP_ATTRS); SearchResult searchResult = null; try { + Profiler profiler = new Profiler(LdapGroupDAO.class); LDAPInterface con = getReadOnlyConnection(); profiler.checkpoint("getGroupNames.getConnection"); searchResult = con.search(searchRequest); @@ -414,7 +396,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } LdapDAO.checkLdapResult(searchResult.getResultCode()); - profiler.checkpoint("checkLdapResult"); +// profiler.checkpoint("checkLdapResult"); return groupNames; } @@ -422,8 +404,8 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO { logger.debug("getGroupNames Exception: " + e1, e1); LdapDAO.checkLdapResult(e1.getResultCode()); - throw new IllegalStateException("Unexpected exception: " + e1 - .getMatchedDN(), e1); + throw new IllegalStateException("Unexpected exception: " + + e1.getMatchedDN(), e1); } } @@ -443,7 +425,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO String[] attrs = GROUP_ATTRS; if (complete) attrs = GROUP_AND_MEMBER_ATTRS; - + Group group = getGroup(getGroupDN(groupID), groupID, attrs); if (complete) @@ -456,7 +438,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO return group; } - // groupID is here so exceptions and loggiong have plain groupID instead of DN + // groupID is here so exceptions and logging have plain groupID instead of DN private Group getGroup(final DN groupDN, final String xgroupID, String[] attributes) throws GroupNotFoundException, TransientException, AccessControlException @@ -465,52 +447,44 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO String loggableGroupID = xgroupID; if (loggableGroupID == null) { - loggableGroupID = groupDN - .toString(); // member or admin group: same name, internal tree + // member or admin group: same name, internal tree + loggableGroupID = groupDN.toString(); } try { - Filter filter = Filter.createNOTFilter(Filter.createPresenceFilter("nsaccountlock")); + Filter filter = Filter.createNOTFilter(Filter.createPresenceFilter(LDAP_NSACCOUNTLOCK)); filter = Filter.createANDFilter(filter, - Filter.createEqualityFilter("entrydn", groupDN.toNormalizedString())); + Filter.createEqualityFilter(LDAP_ENTRYDN, groupDN.toNormalizedString())); SearchRequest searchRequest = new SearchRequest(groupDN.toNormalizedString(), SearchScope.BASE, filter, attributes); - // permissions now checked in LdapGroupPersistence - - //searchRequest.addControl( - // new ProxiedAuthorizationV2RequestControl("dn:" + - // getSubjectDN() - // .toNormalizedString())); - - SearchResultEntry searchEntry = getReadOnlyConnection() .searchForEntry(searchRequest); if (searchEntry == null) { - String msg = "Group not found " + loggableGroupID; - logger.debug(msg + " cause: null"); + String msg = "Group not found " + loggableGroupID + " cause: null"; + logger.debug(msg); throw new GroupNotFoundException(loggableGroupID); } - Group ldapGroup = createGroupFromEntry(searchEntry, attributes); + Group ldapGroup = createGroupFromSearchResult(searchEntry, attributes); - if (searchEntry.getAttributeValues("uniquemember") != null) + if (searchEntry.getAttributeValues(LDAP_UNIQUE_MEMBER) != null) { for (String member : searchEntry - .getAttributeValues("uniquemember")) + .getAttributeValues(LDAP_UNIQUE_MEMBER)) { DN memberDN = new DN(member); if (memberDN.isDescendantOf(config.getUsersDN(), false)) { - User<X500Principal> user; + User user; try { - user = userDAO.getX500User(memberDN); + user = userDAO.getUser(new DNPrincipal(member)); ldapGroup.getUserMembers().add(user); } catch (UserNotFoundException e) @@ -519,8 +493,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO // from groups they belong to } } - else if (memberDN - .isDescendantOf(config.getGroupsDN(), false)) + else if (memberDN.isDescendantOf(config.getGroupsDN(), false)) { try { @@ -584,24 +557,24 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO List<Modification> adminMods = new ArrayList<Modification>(); if (withActivate) { - mods.add(new Modification(ModificationType.DELETE, "nsaccountlock")); - adminMods.add(new Modification(ModificationType.DELETE, "nsaccountlock")); + mods.add(new Modification(ModificationType.DELETE, LDAP_NSACCOUNTLOCK)); + adminMods.add(new Modification(ModificationType.DELETE, LDAP_NSACCOUNTLOCK)); } if (StringUtil.hasText(group.description)) { - mods.add(new Modification(ModificationType.REPLACE, "description", + mods.add(new Modification(ModificationType.REPLACE, LDAP_DESCRIPTION, group.description)); } else { - mods.add(new Modification(ModificationType.REPLACE, "description")); + mods.add(new Modification(ModificationType.REPLACE, LDAP_DESCRIPTION)); } try { Set<String> newMembers = new HashSet<String>(); - for (User<?> member : group.getUserMembers()) + for (User member : group.getUserMembers()) { DN memberDN = userDAO.getUserDN(member); newMembers.add(memberDN.toNormalizedString()); @@ -617,7 +590,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } Set<String> newAdmins = new HashSet<String>(); - for (User<?> member : group.getUserAdmins()) + for (User member : group.getUserAdmins()) { DN memberDN = userDAO.getUserDN(member); newAdmins.add(memberDN.toNormalizedString()); @@ -633,34 +606,24 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } // modify the admin group - adminMods.add(new Modification(ModificationType.REPLACE, "uniquemember", - (String[]) newAdmins - .toArray(new String[newAdmins - .size()]))); + adminMods.add( + new Modification(ModificationType.REPLACE, LDAP_UNIQUE_MEMBER, + (String[]) newAdmins.toArray(new String[newAdmins.size()]))); ModifyRequest adminModify = new ModifyRequest(getAdminGroupDN(group.getID()), adminMods); - //adminModify.addControl( - // new ProxiedAuthorizationV2RequestControl( - // "dn:" + getSubjectDN().toNormalizedString())); - LdapDAO.checkLdapResult( getReadWriteConnection().modify(adminModify).getResultCode()); // modify the group itself - mods.add(new Modification(ModificationType.REPLACE, "uniquemember", - (String[]) newMembers - .toArray(new String[newMembers - .size()]))); + mods.add( + new Modification(ModificationType.REPLACE, LDAP_UNIQUE_MEMBER, + (String[]) newMembers.toArray(new String[newMembers.size()]))); ModifyRequest modifyRequest = new ModifyRequest(getGroupDN(group.getID()), mods); - //modifyRequest.addControl( - // new ProxiedAuthorizationV2RequestControl( - // "dn:" + getSubjectDN().toNormalizedString())); - LdapDAO.checkLdapResult( getReadWriteConnection().modify(modifyRequest).getResultCode()); } @@ -682,8 +645,8 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } catch (GroupNotFoundException e) { - throw new RuntimeException("BUG: modified group not found (" + group - .getID() + ")"); + throw new RuntimeException("BUG: modified group not found (" + + group.getID() + ")"); } } @@ -707,8 +670,8 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO throws GroupNotFoundException, TransientException, AccessControlException { - ModifyRequest clearMembers = new ModifyRequest(groupDN, - new Modification(ModificationType.DELETE, "uniquemember")); + ModifyRequest clearMembers = new ModifyRequest(groupDN, + new Modification(ModificationType.DELETE, LDAP_UNIQUE_MEMBER)); try { logger.debug("clearMembers " + groupDN); @@ -721,9 +684,9 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO LdapDAO.checkLdapResult(e1.getResultCode(), true); } - ModifyRequest deleteGroup = new ModifyRequest(groupDN, - new Modification(ModificationType.ADD, "nsaccountlock", "true")); - + ModifyRequest deleteGroup = new ModifyRequest(groupDN, + new Modification(ModificationType.ADD, LDAP_NSACCOUNTLOCK, "true")); + try { logger.debug("deleteGroup " + groupDN); @@ -753,32 +716,26 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO try { DN userDN = new DN(owner.getName()); - - Filter filter = Filter.createNOTFilter(Filter.createPresenceFilter("nsaccountlock")); - filter = Filter.createANDFilter(filter, - Filter.createEqualityFilter("owner", userDN.toNormalizedString())); + Filter filter = Filter.createNOTFilter(Filter.createPresenceFilter(LDAP_NSACCOUNTLOCK)); + + filter = Filter.createANDFilter(filter, + Filter.createEqualityFilter(LDAP_OWNER, userDN.toNormalizedString())); if (groupID != null) { DN groupDN = getGroupDN(groupID); - filter = Filter.createANDFilter(filter, - Filter.createEqualityFilter("entrydn", groupDN.toNormalizedString())); + filter = Filter.createANDFilter(filter, + Filter.createEqualityFilter(LDAP_ENTRYDN, groupDN.toNormalizedString())); } SearchRequest searchRequest = new SearchRequest( config.getGroupsDN(), SearchScope.SUB, filter, GROUP_ATTRS); - //searchRequest.addControl( - // new ProxiedAuthorizationV2RequestControl("dn:" + - // getSubjectDN() - // .toNormalizedString())); - - SearchResult results = getReadOnlyConnection() - .search(searchRequest); + SearchResult results = getReadOnlyConnection().search(searchRequest); for (SearchResultEntry result : results.getSearchEntries()) { - ret.add(createGroupFromEntry(result, GROUP_ATTRS)); + ret.add(createGroupFromSearchResult(result, GROUP_ATTRS)); } } catch (LDAPException e1) @@ -789,45 +746,46 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO return ret; } - private Group createGroupFromEntry(SearchResultEntry result, String[] attributes) + private Group createGroupFromSearchResult(SearchResultEntry result, String[] attributes) throws LDAPException, TransientException { - if (result.getAttribute("nsaccountlock") != null) + if (result.getAttribute(LDAP_NSACCOUNTLOCK) != null) { - throw new RuntimeException("BUG: found group with nsaccountlock set: " + result - .getAttributeValue("entrydn").toString()); + throw new RuntimeException("BUG: found group with nsaccountlock set: " + + result.getAttributeValue(LDAP_ENTRYDN)); } - String entryDN = result.getAttributeValue("entrydn"); - String groupName = result.getAttributeValue("cn"); + String entryDN = result.getAttributeValue(LDAP_ENTRYDN); + String groupName = result.getAttributeValue(LDAP_CN); if (attributes == PUB_GROUP_ATTRS) { return new Group(groupName); } - DN ownerDN = result.getAttributeValueAsDN("owner"); + String ownerDN = result.getAttributeValue(LDAP_OWNER); if (ownerDN == null) { throw new AccessControlException(groupName); } try { - User owner = userDAO.getX500User(ownerDN); - Group g = new Group(groupName, owner); - if (result.hasAttribute("description")) + User owner = userDAO.getUser(new DNPrincipal(ownerDN)); + Group group = new Group(groupName); + setField(group, owner, LDAP_OWNER); + if (result.hasAttribute(LDAP_DESCRIPTION)) { - g.description = result.getAttributeValue("description"); + group.description = result.getAttributeValue(LDAP_DESCRIPTION); } - if (result.hasAttribute("modifytimestamp")) + if (result.hasAttribute(LDAP_MODIFY_TIMESTAMP)) { - g.lastModified = result - .getAttributeValueAsDate("modifytimestamp"); + group.lastModified = result.getAttributeValueAsDate(LDAP_MODIFY_TIMESTAMP); } - return g; + return group; } catch (UserNotFoundException ex) { - throw new RuntimeException("Invalid state: owner does not exist: " + ownerDN + " group: " + entryDN); + throw new RuntimeException("Invalid state: owner does not exist: " + + ownerDN + " group: " + entryDN); } } @@ -884,4 +842,27 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } } + // set private field using reflection + private void setField(Object object, Object value, String name) + { + try + { + Field field = object.getClass().getDeclaredField(name); + field.setAccessible(true); + field.set(object, value); + } + catch (NoSuchFieldException e) + { + final String error = object.getClass().getSimpleName() + + " field " + name + "not found"; + throw new RuntimeException(error, e); + } + catch (IllegalAccessException e) + { + final String error = "unable to update " + name + " in " + + object.getClass().getSimpleName(); + throw new RuntimeException(error, e); + } + } + } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java index f81f012724ab5581c9dba368d4103a1dbddc84dc..8ce149e9336cb9e5833c5968398a85b802330231 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java @@ -70,7 +70,13 @@ package ca.nrc.cadc.ac.server.ldap; import java.security.AccessControlException; import java.security.Principal; +import java.util.ArrayList; import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import javax.security.auth.Subject; import org.apache.log4j.Logger; @@ -86,14 +92,11 @@ import ca.nrc.cadc.ac.server.GroupPersistence; import ca.nrc.cadc.auth.AuthMethod; import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.DNPrincipal; +import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import javax.security.auth.Subject; +import ca.nrc.cadc.util.ObjectUtil; -public class LdapGroupPersistence<T extends Principal> extends LdapPersistence implements GroupPersistence<T> +public class LdapGroupPersistence extends LdapPersistence implements GroupPersistence { private static final Logger log = Logger.getLogger(LdapGroupPersistence.class); @@ -123,16 +126,15 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i { // current policy: group names visible to all authenticated users Subject caller = AuthenticationUtil.getCurrentSubject(); - if (caller == null || AuthMethod.ANON.equals(AuthenticationUtil.getAuthMethod(caller))) - throw new AccessControlException("Caller is not authenticated"); - - LdapGroupDAO<T> groupDAO = null; - LdapUserDAO<T> userDAO = null; + checkAuthenticatedWithAccount(caller); + + LdapGroupDAO groupDAO = null; + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); - groupDAO = new LdapGroupDAO<T>(conns, userDAO); + userDAO = new LdapUserDAO(conns); + groupDAO = new LdapGroupDAO(conns, userDAO); Collection<String> ret = groupDAO.getGroupNames(); return ret; } @@ -148,14 +150,14 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i { Subject callerSubject = AuthenticationUtil.getCurrentSubject(); boolean allowed = isMember(callerSubject, groupName) || isAdmin(callerSubject, groupName); - - LdapGroupDAO<T> groupDAO = null; - LdapUserDAO<T> userDAO = null; + + LdapGroupDAO groupDAO = null; + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); - groupDAO = new LdapGroupDAO<T>(conns, userDAO); + userDAO = new LdapUserDAO(conns); + groupDAO = new LdapGroupDAO(conns, userDAO); Group ret = groupDAO.getGroup(groupName, true); if (allowed || isOwner(callerSubject, ret)) return ret; @@ -173,14 +175,16 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i GroupNotFoundException { Subject caller = AuthenticationUtil.getCurrentSubject(); - User<Principal> owner = getUser(caller); - group.setOwner(owner); - + checkAuthenticatedWithAccount(caller); + Principal userID = getUser(caller); + LdapConnections conns = new LdapConnections(this); try { - LdapUserDAO<T> userDAO = new LdapUserDAO<T>(conns); - LdapGroupDAO<T> groupDAO = new LdapGroupDAO<T>(conns, userDAO); + LdapUserDAO userDAO = new LdapUserDAO(conns); + User owner = userDAO.getAugmentedUser(userID); + ObjectUtil.setField(group, owner, "owner"); + LdapGroupDAO groupDAO = new LdapGroupDAO(conns, userDAO); groupDAO.addGroup(group); } finally @@ -194,16 +198,16 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i AccessControlException { Subject callerSubject = AuthenticationUtil.getCurrentSubject(); - - LdapGroupDAO<T> groupDAO = null; - LdapUserDAO<T> userDAO = null; + + LdapGroupDAO groupDAO = null; + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); - groupDAO = new LdapGroupDAO<T>(conns, userDAO); + userDAO = new LdapUserDAO(conns); + groupDAO = new LdapGroupDAO(conns, userDAO); Group g = groupDAO.getGroup(groupName, false); - if (isOwner(callerSubject, g)) + if (isOwner(callerSubject, g)) groupDAO.deleteGroup(groupName); else throw new AccessControlException("permission denied"); @@ -220,14 +224,14 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i { Subject callerSubject = AuthenticationUtil.getCurrentSubject(); boolean allowed = isAdmin(callerSubject, group.getID()); - - LdapGroupDAO<T> groupDAO = null; - LdapUserDAO<T> userDAO = null; + + LdapGroupDAO groupDAO = null; + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); - groupDAO = new LdapGroupDAO<T>(conns, userDAO); + userDAO = new LdapUserDAO(conns); + groupDAO = new LdapGroupDAO(conns, userDAO); if (!allowed) { Group g = groupDAO.getGroup(group.getID(), false); @@ -247,27 +251,27 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i } /** - * + * * @param role * @param groupID check membership in a specific group or null to get all groups * @return * @throws UserNotFoundException * @throws GroupNotFoundException * @throws TransientException - * @throws AccessControlException + * @throws AccessControlException */ public Collection<Group> getGroups(Role role, String groupID) throws UserNotFoundException, GroupNotFoundException, TransientException, AccessControlException { Subject caller = AuthenticationUtil.getCurrentSubject(); - + LdapConnections conns = new LdapConnections(this); try { - LdapUserDAO<T> userDAO = new LdapUserDAO<T>(conns); - LdapGroupDAO<T> groupDAO = new LdapGroupDAO<T>(conns, userDAO); - + LdapUserDAO userDAO = new LdapUserDAO(conns); + LdapGroupDAO groupDAO = new LdapGroupDAO(conns, userDAO); + if ( Role.OWNER.equals(role)) { DNPrincipal p = getInternalID(caller); @@ -316,20 +320,20 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i conns.releaseConnections(); } } - + // GroupMemberships cache created by AuthenticatorImpl private List<Group> getGroupCache(Subject caller, Role role) { if (caller == null || AuthMethod.ANON.equals(AuthenticationUtil.getAuthMethod(caller))) throw new AccessControlException("Caller is not authenticated"); - + Set<GroupMemberships> gset = caller.getPrivateCredentials(GroupMemberships.class); if (gset == null || gset.isEmpty()) throw new RuntimeException("BUG: no GroupMemberships cache in Subject"); GroupMemberships gms = gset.iterator().next(); return gms.getMemberships(role); } - + // true if the current subject is a member: using GroupMemberships cache private boolean isMember(Subject caller, String groupName) { @@ -341,7 +345,7 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i } return false; } - + private boolean isAdmin(Subject caller, String groupName) { List<Group> groups = getGroupCache(caller, Role.ADMIN); @@ -352,12 +356,12 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i } return false; } - + private boolean isOwner(Subject caller, Group g) { if (caller == null || AuthMethod.ANON.equals(AuthenticationUtil.getAuthMethod(caller))) throw new AccessControlException("Caller is not authenticated"); - + // check owner for (Principal pc : caller.getPrincipals()) { @@ -374,22 +378,31 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i { if (caller == null || AuthMethod.ANON.equals(AuthenticationUtil.getAuthMethod(caller))) throw new AccessControlException("Caller is not authenticated"); - + Set<DNPrincipal> ds = caller.getPrincipals(DNPrincipal.class); if (ds.isEmpty()) return null; return ds.iterator().next(); } - - private User<Principal> getUser(Subject caller) + + private Principal getUser(Subject caller) { if (caller == null || AuthMethod.ANON.equals(AuthenticationUtil.getAuthMethod(caller))) throw new AccessControlException("Caller is not authenticated"); - + Set<GroupMemberships> gset = caller.getPrivateCredentials(GroupMemberships.class); if (gset == null || gset.isEmpty()) throw new RuntimeException("BUG: no GroupMemberships cache in Subject"); GroupMemberships gms = gset.iterator().next(); - return gms.getUser(); + return gms.getUserID(); + } + + private void checkAuthenticatedWithAccount(Subject caller) + { + if (caller == null || AuthMethod.ANON.equals(AuthenticationUtil.getAuthMethod(caller))) + throw new AccessControlException("Caller is not authenticated"); + + if (caller.getPrincipals(HttpPrincipal.class).isEmpty()) + throw new AccessControlException("Caller does not have authorized account"); } } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapPersistence.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapPersistence.java index a8f2b0cebe16cd628c8b8d81315912b3a80854bf..37b1e4f92847ca9cee5cc9b72879022857cce60b 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapPersistence.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapPersistence.java @@ -97,8 +97,6 @@ public abstract class LdapPersistence private static final String LDAP_POOL_JNDI_NAME = ConnectionPools.class.getName(); private static final int POOL_CHECK_INTERVAL_MILLESCONDS = 10000; // 10 seconds - Profiler profiler = new Profiler(LdapPersistence.class); - // static monitor is required for when multiple LdapPersistence objects // are created. private static Object jndiMonitor = new Object(); @@ -115,7 +113,7 @@ public abstract class LdapPersistence ConnectionPools pools = lookupPools(); if (pools == null || pools.isClosed()) throw new IllegalStateException("Pools are closed."); - poolCheck(pools); + pools = poolCheck(pools); return pools.getPools().get(poolName); } catch (NamingException e) @@ -208,6 +206,7 @@ public abstract class LdapPersistence } if (pools == null) { + Profiler profiler = new Profiler(LdapPersistence.class); LdapConfig config = LdapConfig.getLdapConfig(); pools = createPools(config); InitialContext ic = new InitialContext(); @@ -238,13 +237,14 @@ public abstract class LdapPersistence private ConnectionPools createPools(LdapConfig config) { + Profiler profiler = new Profiler(LdapPersistence.class); Map<String,LdapConnectionPool> poolMap = new HashMap<String,LdapConnectionPool>(3); poolMap.put(POOL_READONLY, new LdapConnectionPool( - config, config.getReadOnlyPool(), POOL_READONLY, true)); + config, config.getReadOnlyPool(), POOL_READONLY, true, true)); poolMap.put(POOL_READWRITE, new LdapConnectionPool( - config, config.getReadWritePool(), POOL_READWRITE, true)); + config, config.getReadWritePool(), POOL_READWRITE, true, false)); poolMap.put(POOL_UNBOUNDREADONLY, new LdapConnectionPool( - config, config.getUnboundReadOnlyPool(), POOL_UNBOUNDREADONLY, false)); + config, config.getUnboundReadOnlyPool(), POOL_UNBOUNDREADONLY, false, true)); profiler.checkpoint("Created 3 LDAP connection pools"); return new ConnectionPools(poolMap, config); } @@ -262,7 +262,7 @@ public abstract class LdapPersistence } } - private void poolCheck(ConnectionPools pools) throws TransientException + private ConnectionPools poolCheck(ConnectionPools pools) throws TransientException { if (timeToCheckPools(pools)) { @@ -276,8 +276,10 @@ public abstract class LdapPersistence else { logger.debug("Detected ldap configuration change, rebuilding pools"); + Profiler profiler = new Profiler(LdapPersistence.class); boolean poolRecreated = false; final ConnectionPools oldPools = pools; + ConnectionPools newPools = null; synchronized (jndiMonitor) { @@ -287,7 +289,7 @@ public abstract class LdapPersistence { try { - ConnectionPools newPools = createPools(newConfig); + newPools = createPools(newConfig); newPools.setLastPoolCheck(System.currentTimeMillis()); InitialContext ic = new InitialContext(); try @@ -326,9 +328,13 @@ public abstract class LdapPersistence }; Thread closePoolsThread = new Thread(closeOldPools); closePoolsThread.start(); + + return newPools; } } } + // just return the existing pools + return pools; } private boolean timeToCheckPools(ConnectionPools pools) diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java index 16575184e555a23c81529c4fd07542d87f83a8c4..8dcebdcf9d46fae9011bf47cb6132ed63051008b 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java @@ -68,6 +68,8 @@ */ package ca.nrc.cadc.ac.server.ldap; +import java.net.URI; +import java.net.URISyntaxException; import java.security.AccessControlException; import java.security.Principal; import java.util.ArrayList; @@ -78,27 +80,28 @@ import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; +import java.util.UUID; import javax.security.auth.x500.X500Principal; import org.apache.log4j.Logger; +import ca.nrc.cadc.ac.AC; import ca.nrc.cadc.ac.Group; +import ca.nrc.cadc.ac.InternalID; import ca.nrc.cadc.ac.PersonalDetails; -import ca.nrc.cadc.ac.PosixDetails; import ca.nrc.cadc.ac.Role; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserAlreadyExistsException; -import ca.nrc.cadc.ac.UserDetails; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.ac.UserRequest; import ca.nrc.cadc.ac.client.GroupMemberships; -import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.DNPrincipal; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.profiler.Profiler; +import ca.nrc.cadc.util.ObjectUtil; import ca.nrc.cadc.util.StringUtil; import com.unboundid.ldap.sdk.AddRequest; @@ -129,18 +132,24 @@ import com.unboundid.ldap.sdk.extensions.PasswordModifyExtendedResult; /** * * @author pdowler - * @param <T> */ -public class LdapUserDAO<T extends Principal> extends LdapDAO +public class LdapUserDAO extends LdapDAO { + public static final String EMAIL_ADDRESS_CONFLICT_MESSAGE = + "email address "; + private static final Logger logger = Logger.getLogger(LdapUserDAO.class); - private final Profiler profiler = new Profiler(LdapUserDAO.class); + private String internalIdUriPrefix = AC.USER_URI; // Map of identity type to LDAP attribute private final Map<Class<?>, String> userLdapAttrib = new HashMap<Class<?>, String>(); - // Returned User attributes + // User cn and sn values for users without a HttpPrincipal + protected static final String EXTERNAL_USER_CN = "$EXTERNAL-CN"; + protected static final String EXTERNAL_USER_SN = "$EXTERNAL-SN"; + + // LDAP User attributes protected static final String LDAP_OBJECT_CLASS = "objectClass"; protected static final String LDAP_INET_USER = "inetuser"; protected static final String LDAP_INET_ORG_PERSON = "inetOrgPerson"; @@ -148,9 +157,8 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO 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_USER_NAME = "cn"; protected static final String LDAP_DISTINGUISHED_NAME = "distinguishedName"; - protected static final String LDAP_NUMERICID = "numericid"; protected static final String LADP_USER_PASSWORD = "userPassword"; protected static final String LDAP_FIRST_NAME = "givenName"; protected static final String LDAP_LAST_NAME = "sn"; @@ -160,6 +168,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO protected static final String LDAP_EMAIL = "email"; protected static final String LDAP_INSTITUTE = "institute"; protected static final String LDAP_UID = "uid"; + protected static final String USER_ID = "id"; private String[] userAttribs = new String[] { @@ -172,16 +181,17 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO }; private String[] identityAttribs = new String[] { - LDAP_UID, LDAP_DISTINGUISHED_NAME, LDAP_NUMERICID, LDAP_ENTRYDN, - LDAP_MEMBEROF // for group cache + LDAP_UID, LDAP_DISTINGUISHED_NAME, LDAP_ENTRYDN, + LDAP_USER_NAME, LDAP_MEMBEROF // for group cache }; public LdapUserDAO(LdapConnections connections) { super(connections); - this.userLdapAttrib.put(HttpPrincipal.class, LDAP_UID); + this.userLdapAttrib.put(HttpPrincipal.class, LDAP_USER_NAME); this.userLdapAttrib.put(X500Principal.class, LDAP_DISTINGUISHED_NAME); - this.userLdapAttrib.put(NumericPrincipal.class, LDAP_NUMERICID); + this.userLdapAttrib.put(NumericPrincipal.class, LDAP_UID); + this.userLdapAttrib.put(DNPrincipal.class, LDAP_ENTRYDN); // add the id attributes to user and member attributes String[] princs = userLdapAttrib.values() @@ -206,15 +216,18 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO * @param password password to verify. * @return Boolean * @throws TransientException - * @throws UserNotFoundExceptionjoellama + * @throws UserNotFoundException */ public Boolean doLogin(final String username, final String password) throws TransientException, UserNotFoundException { try { + HttpPrincipal httpPrincipal = new HttpPrincipal(username); + User user = getUser(httpPrincipal); + long uuid = uuid2long(user.getID().getUUID()); BindRequest bindRequest = new SimpleBindRequest( - getUserDN(username, config.getUsersDN()), new String(password)); + getUserDN(uuid, config.getUsersDN()), new String(password)); LDAPConnection conn = this.getUnboundReadConnection(); BindResult bindResult = conn.bind(bindRequest); @@ -228,6 +241,10 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO throw new AccessControlException("Invalid username or password"); } } + catch (UserNotFoundException e) + { + throw new AccessControlException("Invalid username"); + } catch (LDAPException e) { logger.debug("doLogin Exception: " + e, e); @@ -252,23 +269,108 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO /** * Add the specified user to the active user tree. * - * @param userRequest The user to add. + * @param user The user to add. * @throws TransientException If an temporary, unexpected problem occurred. * @throws UserAlreadyExistsException If the user already exists. */ - public void addUser(final UserRequest<T> userRequest) - throws TransientException, UserAlreadyExistsException + public void addUser(final User user) + throws TransientException, UserAlreadyExistsException { + Set<Principal> principals = user.getIdentities(); + if (principals.isEmpty()) + { + throw new IllegalArgumentException("addUser: No user identities"); + } + + if (user.posixDetails != null) + { + throw new UnsupportedOperationException("addUser: Support for users PosixDetails not available"); + } + + Set<X500Principal> x500Principals = user.getIdentities(X500Principal.class); + if (x500Principals.isEmpty()) + { + throw new IllegalArgumentException("addUser: No user X500Principals found"); + } + X500Principal idForLogging = x500Principals.iterator().next(); + + // check current users + for (Principal p : principals) + { + checkUsers(p, null, config.getUsersDN()); + } + try { - getUser(userRequest.getUser().getUserID(), config.getUsersDN()); - final String error = userRequest.getUser().getUserID().getName() + - " found in " + config.getUsersDN(); + long numericID = genNextNumericId(); + String password = UUID.randomUUID().toString(); + + List<Attribute> attributes = new ArrayList<Attribute>(); + addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_INET_ORG_PERSON); + addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_INET_USER); + addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_CADC_ACCOUNT); + addAttribute(attributes, LDAP_UID, String.valueOf(numericID)); + addAttribute(attributes, LDAP_USER_NAME, EXTERNAL_USER_CN); + addAttribute(attributes, LDAP_LAST_NAME, EXTERNAL_USER_SN); + addAttribute(attributes, LADP_USER_PASSWORD, password); + for (X500Principal p : x500Principals) + { + addAttribute(attributes, LDAP_DISTINGUISHED_NAME, p.getName()); + } + + DN userDN = getUserDN(numericID, config.getUsersDN()); + AddRequest addRequest = new AddRequest(userDN, attributes); + logger.debug("addUser: adding " + idForLogging.getName() + " to " + config.getUsersDN()); + LDAPResult result = getReadWriteConnection().add(addRequest); + LdapDAO.checkLdapResult(result.getResultCode()); + } + catch (LDAPException e) + { + logger.error("addUser Exception: " + e, e); + LdapUserDAO.checkUserLDAPResult(e.getResultCode()); + throw new RuntimeException("Unexpected LDAP exception", e); + } + } + + private String getEmailAddress(final User user) + { + if (user.personalDetails == null) + { + String error = user.getHttpPrincipal().getName() + " missing required PersonalDetails"; + throw new IllegalArgumentException(error); + } + + if (!StringUtil.hasText(user.personalDetails.email)) + { + String error = user.getHttpPrincipal().getName() + " missing required email address"; + throw new IllegalArgumentException(error); + } + return user.personalDetails.email; + } + + private void checkUsers(final Principal userID, final String email, final String usersDN) + throws TransientException, UserAlreadyExistsException + { + // check current users + try + { + getUser(userID, usersDN); + final String error = "user " + userID.getName() + " found in " + usersDN; throw new UserAlreadyExistsException(error); } - catch (UserNotFoundException e1) {} + catch (UserNotFoundException ok) { } - addUser(userRequest, config.getUsersDN()); + // check if email address is already in use + if (email != null) + { + try + { + getUserByEmailAddress(email, usersDN); + final String error = "user " + userID.getName() + " found in " + usersDN; + throw new UserAlreadyExistsException(error); + } + catch (UserNotFoundException ok) { } + } } /** @@ -278,53 +380,56 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO * @throws TransientException If an temporary, unexpected problem occurred. * @throws UserAlreadyExistsException If the user already exists. */ - public void addPendingUser(final UserRequest<T> userRequest) + public void addUserRequest(final UserRequest userRequest) throws TransientException, UserAlreadyExistsException { - // check current users - try + final User user = userRequest.getUser(); + final HttpPrincipal userID = user.getHttpPrincipal(); + if (userID == null) { - getUser(userRequest.getUser().getUserID(), config.getUsersDN(), false); - final String error = userRequest.getUser().getUserID().getName() + - " found in " + config.getUsersDN(); - throw new UserAlreadyExistsException(error); + throw new IllegalArgumentException("User missing required HttpPrincipal type"); } - catch (UserNotFoundException ok) { } - // check pending users - try + if (userID.getName().startsWith("$")) { - getUser(userRequest.getUser().getUserID(), config.getUserRequestsDN(), false); - final String error = userRequest.getUser().getUserID().getName() + - " found in " + config.getUserRequestsDN(); - throw new UserAlreadyExistsException(error); + final String error = "addUserRequest: username " + user.getHttpPrincipal().getName() + + " cannot start with a $"; + throw new IllegalArgumentException(error); } - catch (UserNotFoundException ok) { } - addUser(userRequest, config.getUserRequestsDN()); - } - - private void addUser(final UserRequest<T> userRequest, final String usersDN) - throws TransientException, UserAlreadyExistsException - { - final User<T> user = userRequest.getUser(); - final Class userType = user.getUserID().getClass(); - final String searchField = userLdapAttrib.get(userType); - - if (searchField == null) + if (user.posixDetails != null) { - throw new IllegalArgumentException("Unsupported principal type " + userType); + throw new UnsupportedOperationException("Support for users PosixDetails not available"); } + // email is required + String email = getEmailAddress(user); + + // check current users + checkUsers(userID, email, config.getUsersDN()); + + // check user requests + checkUsers(userID, email, config.getUserRequestsDN()); + try { + long numericID = genNextNumericId(); + List<Attribute> attributes = new ArrayList<Attribute>(); addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_INET_ORG_PERSON); addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_INET_USER); addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_CADC_ACCOUNT); - addAttribute(attributes, LDAP_COMMON_NAME, user.getUserID().getName()); + addAttribute(attributes, LDAP_UID, String.valueOf(numericID)); + addAttribute(attributes, LDAP_USER_NAME, userID.getName()); + addAttribute(attributes, LDAP_LAST_NAME, user.personalDetails.getLastName()); addAttribute(attributes, LADP_USER_PASSWORD, new String(userRequest.getPassword())); - addAttribute(attributes, LDAP_NUMERICID, String.valueOf(genNextNumericId())); + addAttribute(attributes, LDAP_FIRST_NAME, user.personalDetails.getFirstName()); + addAttribute(attributes, LDAP_ADDRESS, user.personalDetails.address); + addAttribute(attributes, LDAP_CITY, user.personalDetails.city); + addAttribute(attributes, LDAP_COUNTRY, user.personalDetails.country); + addAttribute(attributes, LDAP_EMAIL, email); + addAttribute(attributes, LDAP_INSTITUTE, user.personalDetails.institute); + for (Principal princ : user.getIdentities()) { if (princ instanceof X500Principal) @@ -332,41 +437,23 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO addAttribute(attributes, LDAP_DISTINGUISHED_NAME, princ.getName()); } } - 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) - { - throw new UnsupportedOperationException( - "Support for users PosixDetails not available"); - } - } - DN userDN = getUserDN(user.getUserID().getName(), usersDN); + DN userDN = getUserDN(numericID, config.getUserRequestsDN()); AddRequest addRequest = new AddRequest(userDN, attributes); + logger.debug("addUserRequest: adding " + userID.getName() + " to " + config.getUserRequestsDN()); LDAPResult result = getReadWriteConnection().add(addRequest); LdapDAO.checkLdapResult(result.getResultCode()); } catch (LDAPException e) { - logger.error("addUser Exception: " + e, e); + logger.error("addUserRequest Exception: " + e, e); LdapUserDAO.checkUserLDAPResult(e.getResultCode()); throw new RuntimeException("Unexpected LDAP exception", e); } } /** - * Get the user specified by userID. + * Get the user specified by the userID. * * @param userID The userID. * @return User instance. @@ -374,9 +461,9 @@ 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(final T userID) - throws UserNotFoundException, TransientException, - AccessControlException + public User getUser(final Principal userID) + throws UserNotFoundException, TransientException, + AccessControlException { return getUser(userID, config.getUsersDN()); } @@ -391,9 +478,9 @@ 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> getPendingUser(final T userID) - throws UserNotFoundException, TransientException, - AccessControlException + public User getUserRequest(final Principal userID) + throws UserNotFoundException, TransientException, + AccessControlException { return getUser(userID, config.getUserRequestsDN()); } @@ -408,27 +495,9 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - private User<T> getUser(final T userID, final String usersDN) + private User getUser(final Principal userID, final String usersDN) throws UserNotFoundException, TransientException, - AccessControlException - { - - return getUser(userID, usersDN, true); - } - /** - * Get the user specified by userID. - * - * @param userID The userID. - * @param usersDN The LDAP tree to search. - * @param proxy Whether to proxy the search as the calling Subject. - * @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. - */ - private User<T> getUser(final T userID, final String usersDN, final boolean proxy) - throws UserNotFoundException, TransientException, - AccessControlException + AccessControlException { String searchField = userLdapAttrib.get(userID.getClass()); if (searchField == null) @@ -438,124 +507,231 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO } SearchResultEntry searchResult = null; - Filter filter = null; try { - filter = Filter.createEqualityFilter(searchField, userID.getName()); - logger.debug("search filter: " + filter); - - SearchRequest searchRequest = - new SearchRequest(usersDN, SearchScope.ONE, filter, userAttribs); + String name; + if (userID instanceof NumericPrincipal) + { + name = String.valueOf(uuid2long(UUID.fromString(userID.getName()))); + } + else + { + name = userID.getName(); + } + Filter notFilter = Filter.createNOTFilter(Filter.createPresenceFilter(LDAP_NSACCOUNTLOCK)); + Filter equalsFilter = Filter.createEqualityFilter(searchField, name); + Filter filter = Filter.createANDFilter(notFilter, equalsFilter); + logger.debug("getUser: search filter = " + filter); - //if (proxy) - //{ - // String proxyDN = "dn:" + getSubjectDN().toNormalizedString(); - // logger.debug("Proxying auth as: " + proxyDN); - // searchRequest.addControl(new ProxiedAuthorizationV2RequestControl(proxyDN)); - //} + SearchRequest searchRequest = new SearchRequest(usersDN, SearchScope.ONE, filter, userAttribs); searchResult = getReadOnlyConnection().searchForEntry(searchRequest); + if (searchResult == null) + { + String msg = "getUser: user " + userID.toString() + " not found in " + usersDN; + logger.debug(msg); + throw new UserNotFoundException(msg); + } } catch (LDAPException e) { LdapDAO.checkLdapResult(e.getResultCode()); } - if (searchResult == null) + User user = new User(); + String username = searchResult.getAttributeValue(userLdapAttrib.get(HttpPrincipal.class)); + logger.debug("getUser: username = " + username); + if (username != null) + { + user.getIdentities().add(new HttpPrincipal(username)); + } + + String uid = searchResult.getAttributeValue(userLdapAttrib.get(NumericPrincipal.class)); + logger.debug("getUser: uid = " + uid); + if (uid == null) + { + // If the numeric ID does not return it means the user + // does not have permission + throw new AccessControlException("Permission denied"); + } + + InternalID internalID = getInternalID(uid); + ObjectUtil.setField(user, internalID, USER_ID); + user.getIdentities().add(new NumericPrincipal(internalID.getUUID())); + + String x500str = searchResult.getAttributeValue(userLdapAttrib.get(X500Principal.class)); + logger.debug("getUser: x500principal = " + x500str); + if (x500str != null) { - // determine if the user is not there of if the calling user - // doesn't have permission to see it + user.getIdentities().add(new X500Principal(x500str)); + } + + String firstName = searchResult.getAttributeValue(LDAP_FIRST_NAME); + String lastName = searchResult.getAttributeValue(LDAP_LAST_NAME); + if (StringUtil.hasLength(firstName) && StringUtil.hasLength(lastName)) + { + user.personalDetails = new PersonalDetails(firstName, lastName); + user.personalDetails.address = searchResult.getAttributeValue(LDAP_ADDRESS); + user.personalDetails.city = searchResult.getAttributeValue(LDAP_CITY); + user.personalDetails.country = searchResult.getAttributeValue(LDAP_COUNTRY); + user.personalDetails.email = searchResult.getAttributeValue(LDAP_EMAIL); + user.personalDetails.institute = searchResult.getAttributeValue(LDAP_INSTITUTE); + } + + logger.debug("getUser: found " + userID.getName() + " in " + usersDN); + return user; + } + + /** + * Get the user specified by the email address exists. + * + * @param emailAddress The user's email address. + * + * @return User instance. + * + * @throws UserNotFoundException when the user is not found in the main tree. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + * @throws UserAlreadyExistsException A user with the same email address already exists + */ + public User getUserByEmailAddress(final String emailAddress) + throws UserNotFoundException, TransientException, + AccessControlException, UserAlreadyExistsException + { + return getUserByEmailAddress(emailAddress, config.getUsersDN()); + } + + /** + * Get the user specified by the email address exists. + * + * @param emailAddress The user's email address. + * @param usersDN The LDAP tree to search. + * @return User ID + * @throws UserNotFoundException when the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + * @throws UserAlreadyExistsException A user with the same email address already exists + */ + private User getUserByEmailAddress(final String emailAddress, final String usersDN) + throws UserNotFoundException, TransientException, + AccessControlException + { + SearchResultEntry searchResult = null; + Filter filter = null; + try + { + Filter notFilter = Filter.createNOTFilter(Filter.createPresenceFilter(LDAP_NSACCOUNTLOCK)); + Filter equalsFilter = Filter.createEqualityFilter("email", emailAddress); + filter = Filter.createANDFilter(notFilter, equalsFilter); + logger.debug("search filter: " + filter); + SearchRequest searchRequest = new SearchRequest(usersDN, SearchScope.ONE, filter, userAttribs); - try - { - searchResult = getReadOnlyConnection().searchForEntry(searchRequest); - } - catch (LDAPException e) - { - LdapDAO.checkLdapResult(e.getResultCode()); - } + + searchResult = getReadOnlyConnection().searchForEntry(searchRequest); if (searchResult == null) { - String msg = "User not found " + userID.toString(); + String msg = "getUserByEmailAddress: user with email address " + + emailAddress + " not found"; logger.debug(msg); throw new UserNotFoundException(msg); } - throw new AccessControlException("Permission denied"); } - - User<T> user = new User<T>(userID); - String username = searchResult.getAttributeValue(userLdapAttrib.get(HttpPrincipal.class)); - logger.debug("username: " + username); - user.getIdentities().add(new HttpPrincipal(username)); - - Integer numericID = searchResult.getAttributeValueAsInteger(userLdapAttrib.get(NumericPrincipal.class)); - logger.debug("Numeric id: " + numericID); - if (numericID == null) + catch (LDAPException e) { - // If the numeric ID does not return it means the user - // does not have permission - throw new AccessControlException("Permission denied"); + LdapDAO.checkLdapResult(e.getResultCode()); } - user.getIdentities().add(new NumericPrincipal(numericID)); + + String userIDString = searchResult.getAttributeValue(LDAP_USER_NAME); + HttpPrincipal userID = new HttpPrincipal(userIDString); + User user = new User(); + user.getIdentities().add(userID); + + // Set the User's private InternalID field + String numericID = searchResult.getAttributeValue(userLdapAttrib.get(NumericPrincipal.class)); + InternalID internalID = getInternalID(numericID); + ObjectUtil.setField(user, internalID, USER_ID); + user.getIdentities().add(new NumericPrincipal(internalID.getUUID())); String x500str = searchResult.getAttributeValue(userLdapAttrib.get(X500Principal.class)); - logger.debug("x500principal: " + x500str); + logger.debug("getUserByEmailAddress: x500principal = " + x500str); if (x500str != null) user.getIdentities().add(new X500Principal(x500str)); - 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); + String firstName = searchResult.getAttributeValue(LDAP_FIRST_NAME); + String lastName = searchResult.getAttributeValue(LDAP_LAST_NAME); + if (StringUtil.hasLength(firstName) && StringUtil.hasLength(lastName)) + { + user.personalDetails = new PersonalDetails(firstName, lastName); + user.personalDetails.address = searchResult.getAttributeValue(LDAP_ADDRESS); + user.personalDetails.city = searchResult.getAttributeValue(LDAP_CITY); + user.personalDetails.country = searchResult.getAttributeValue(LDAP_COUNTRY); + user.personalDetails.email = searchResult.getAttributeValue(LDAP_EMAIL); + user.personalDetails.institute = searchResult.getAttributeValue(LDAP_INSTITUTE); + } return user; } - public User<T> getAugmentedUser(final T userID) + public User getAugmentedUser(final Principal userID) throws UserNotFoundException, TransientException { + Profiler profiler = new Profiler(LdapUserDAO.class); String searchField = userLdapAttrib.get(userID.getClass()); - profiler.checkpoint("getAugmentedUser.getSearchField"); if (searchField == null) { - throw new IllegalArgumentException( - "Unsupported principal type " + userID.getClass()); + throw new IllegalArgumentException("getAugmentedUser: unsupported principal type " + + userID.getClass()); } try { - Filter filter = Filter.createEqualityFilter(searchField, userID.getName()); + String name; + if (userID instanceof NumericPrincipal) + { + name = String.valueOf(uuid2long(UUID.fromString(userID.getName()))); + } + else + { + name = userID.getName(); + } + + Filter notFilter = Filter.createNOTFilter(Filter.createPresenceFilter(LDAP_NSACCOUNTLOCK)); + Filter equalsFilter = Filter.createEqualityFilter(searchField, name); + Filter filter = Filter.createANDFilter(notFilter, equalsFilter); + profiler.checkpoint("getAugmentedUser.createFilter"); - logger.debug("search filter: " + filter); + logger.debug("getAugmentedUser: search filter = " + filter); SearchRequest searchRequest = new SearchRequest( config.getUsersDN(), SearchScope.ONE, filter, identityAttribs); - profiler.checkpoint("getAugmentedUser.createSearchRequest"); - SearchResultEntry searchResult = getReadOnlyConnection().searchForEntry(searchRequest); + LDAPConnection con = getReadOnlyConnection(); + profiler.checkpoint("getAugmentedUser.getReadOnlyConnection"); + SearchResultEntry searchResult = con.searchForEntry(searchRequest); profiler.checkpoint("getAugmentedUser.searchForEntry"); if (searchResult == null) { - String msg = "User not found " + userID.toString(); + String msg = "getAugmentedUser: user " + name + " not found"; logger.debug(msg); throw new UserNotFoundException(msg); } - User<T> user = new User<T>(userID); - user.getIdentities().add(new HttpPrincipal( - searchResult.getAttributeValue(LDAP_UID))); - int numericID = searchResult.getAttributeValueAsInteger(LDAP_NUMERICID); - logger.debug("numericID is " + numericID); - user.getIdentities().add(new NumericPrincipal(numericID)); + User user = new User(); + String username = searchResult.getAttributeValue(LDAP_USER_NAME); + logger.debug("getAugmentedUser: username = " + username); + user.getIdentities().add(new HttpPrincipal(username)); + + String numericID = searchResult.getAttributeValue(LDAP_UID); + logger.debug("getAugmentedUser: numericID = " + numericID); + + InternalID internalID = getInternalID(numericID); + ObjectUtil.setField(user, internalID, USER_ID); + user.getIdentities().add(new NumericPrincipal(internalID.getUUID())); + String dn = searchResult.getAttributeValue(LDAP_DISTINGUISHED_NAME); if (dn != null) { @@ -564,7 +740,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO user.getIdentities().add(new DNPrincipal(searchResult.getAttributeValue(LDAP_ENTRYDN))); // cache memberOf values in the user - GroupMemberships gms = new GroupMemberships(user); + GroupMemberships gms = new GroupMemberships(userID); user.appData = gms; // add even if empty String[] mems = searchResult.getAttributeValues(LDAP_MEMBEROF); if (mems != null && mems.length > 0) @@ -585,11 +761,12 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO gms.add(memberOf, Role.MEMBER); } profiler.checkpoint("getAugmentedUser.mapIdentities"); + logger.debug("getAugmentedUser: returning user " + userID.getName()); return user; } catch (LDAPException e) { - logger.debug("getGroup Exception: " + e, e); + logger.debug("getAugmentedUser Exception: " + e, e); LdapDAO.checkLdapResult(e.getResultCode()); throw new RuntimeException("BUG: checkLdapResult didn't throw an exception"); } @@ -618,7 +795,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO * @return A Collection of User's. * @throws TransientException If an temporary, unexpected problem occurred. */ - public Collection<User<Principal>> getUsers() + public Collection<User> getUsers() throws AccessControlException, TransientException { return getUsers(config.getUsersDN()); @@ -630,22 +807,24 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO * @return A Collection of User's. * @throws TransientException If an temporary, unexpected problem occurred. */ - public Collection<User<Principal>> getPendingUsers() + public Collection<User> getUserRequests() throws AccessControlException, TransientException { return getUsers(config.getUserRequestsDN()); } - private Collection<User<Principal>> getUsers(final String usersDN) + private Collection<User> getUsers(final String usersDN) throws AccessControlException, TransientException { - final Collection<User<Principal>> users = new ArrayList<User<Principal>>(); + final Collection<User> users = new ArrayList<User>(); - Filter filter = Filter.createPresenceFilter(LDAP_UID); + Filter notFilter = Filter.createNOTFilter(Filter.createPresenceFilter(LDAP_NSACCOUNTLOCK)); + Filter presenceFilter = Filter.createPresenceFilter(LDAP_UID); + Filter filter = Filter.createANDFilter(notFilter, presenceFilter); logger.debug("search filter: " + filter); final String[] attributes = new String[] - { LDAP_UID, LDAP_FIRST_NAME, LDAP_LAST_NAME }; + { LDAP_USER_NAME, LDAP_FIRST_NAME, LDAP_LAST_NAME }; final SearchRequest searchRequest = new SearchRequest(usersDN, SearchScope.ONE, filter, attributes); @@ -658,17 +837,19 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO for (SearchResultEntry next : searchResult.getSearchEntries()) { final String firstName = - next.getAttributeValue(LDAP_FIRST_NAME).trim(); + next.getAttributeValue(LDAP_FIRST_NAME); final String lastName = next.getAttributeValue(LDAP_LAST_NAME).trim(); - final String uid = next.getAttributeValue(LDAP_UID).trim(); - User<Principal> user = new User<Principal>(new HttpPrincipal(uid)); + final String username = next.getAttributeValue(LDAP_USER_NAME); + + User user = new User(); + user.getIdentities().add(new HttpPrincipal(username)); // Only add Personal Details if it is relevant. - if (StringUtil.hasLength(firstName) - && StringUtil.hasLength(lastName)) + if (StringUtil.hasLength(firstName) && + StringUtil.hasLength(lastName)) { - user.details.add(new PersonalDetails(firstName, lastName)); + user.personalDetails = new PersonalDetails(firstName.trim(), lastName.trim()); } users.add(user); @@ -683,7 +864,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO throw new IllegalStateException(message); } } - + logger.debug("getUsers: found " + users.size() + " in " + usersDN); return users; } @@ -697,18 +878,15 @@ 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> approvePendingUser(final T userID) + public User approveUserRequest(final Principal userID) throws UserNotFoundException, TransientException, AccessControlException { - User<T> pendingUser = getPendingUser(userID); - - Set<HttpPrincipal> httpPrincipals = pendingUser.getIdentities(HttpPrincipal.class); - if (httpPrincipals.isEmpty()) + User userRequest = getUserRequest(userID); + if (userRequest.getHttpPrincipal() == null) { throw new RuntimeException("BUG: missing HttpPrincipal for " + userID.getName()); } - HttpPrincipal httpPrincipal = httpPrincipals.iterator().next(); - String uid = "uid=" + httpPrincipal.getName(); + String uid = "uid=" + uuid2long(userRequest.getID().getUUID()); String dn = uid + "," + config.getUserRequestsDN(); try @@ -725,7 +903,9 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO } try { - return getUser(userID); + User user = getUser(userID); + logger.debug("approvedUserRequest: " + userID.getName()); + return user; } catch (UserNotFoundException e) { @@ -737,40 +917,39 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO /** * Update the user specified by User. * - * @param userID + * @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(final User<T> userID) + public User modifyUser(final User user) throws UserNotFoundException, TransientException, AccessControlException { - User existingUser = getUser(userID.getUserID()); + // Will we always have a HttpPrincipal? + User existingUser = getUser(user.getHttpPrincipal()); List<Modification> mods = new ArrayList<Modification>(); - for (UserDetails details : userID.details) + + if (user.personalDetails != null) { - if (details.getClass() == PersonalDetails.class) - { - PersonalDetails pd = (PersonalDetails) details; - addModification(mods, LDAP_FIRST_NAME, pd.getFirstName()); - addModification(mods, LDAP_LAST_NAME, pd.getLastName()); - addModification(mods, LDAP_ADDRESS, pd.address); - addModification(mods, LDAP_CITY, pd.city); - addModification(mods, LDAP_COUNTRY, pd.country); - addModification(mods, LDAP_EMAIL, pd.email); - addModification(mods, LDAP_INSTITUTE, pd.institute); - } - else if (details.getClass() == PosixDetails.class) - { - throw new UnsupportedOperationException( - "Support for users PosixDetails not available"); - } + addModification(mods, LDAP_FIRST_NAME, user.personalDetails.getFirstName()); + addModification(mods, LDAP_LAST_NAME, user.personalDetails.getLastName()); + addModification(mods, LDAP_ADDRESS, user.personalDetails.address); + addModification(mods, LDAP_CITY, user.personalDetails.city); + addModification(mods, LDAP_COUNTRY, user.personalDetails.country); + addModification(mods, LDAP_EMAIL, user.personalDetails.email); + addModification(mods, LDAP_INSTITUTE, user.personalDetails.institute); + } + + if (user.posixDetails != null) + { + throw new UnsupportedOperationException( + "Support for users PosixDetails not available"); } // set the x500 DNs if there - Set<X500Principal> x500Principals = userID.getIdentities(X500Principal.class); + Set<X500Principal> x500Principals = user.getIdentities(X500Principal.class); if (x500Principals != null && !x500Principals.isEmpty()) { Iterator<X500Principal> i = x500Principals.iterator(); @@ -784,7 +963,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO try { - ModifyRequest modifyRequest = new ModifyRequest(getUserDN(userID), mods); + ModifyRequest modifyRequest = new ModifyRequest(getUserDN(user), mods); //modifyRequest.addControl( // new ProxiedAuthorizationV2RequestControl( // "dn:" + getSubjectDN().toNormalizedString())); @@ -797,31 +976,24 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO } try { - return getUser(userID.getUserID()); + User ret = getUser(user.getHttpPrincipal()); + logger.debug("ModifiedUser: " + user.getHttpPrincipal().getName()); + return ret; } catch (UserNotFoundException e) { throw new RuntimeException( - "BUG: modified user not found (" + userID.getUserID() + ")"); + "BUG: modified user not found (" + user.getHttpPrincipal().getName() + ")"); } } - /** - * Update a user's password. The given user and authenticating user must match. - * - * @param userID - * @param oldPassword current password. - * @param newPassword new password. - * @throws UserNotFoundException If the given user does not exist. - * @throws TransientException If an temporary, unexpected problem occurred. - * @throws AccessControlException If the operation is not permitted. - */ - public void setPassword(HttpPrincipal userID, String oldPassword, String newPassword) - throws UserNotFoundException, TransientException, AccessControlException + protected void updatePassword(HttpPrincipal userID, String oldPassword, String newPassword) + throws UserNotFoundException, TransientException, AccessControlException { try { - User user = new User(userID); + User user = new User(); + user.getIdentities().add(userID); DN userDN = getUserDN(user); //BindRequest bindRequest = new SimpleBindRequest( @@ -830,15 +1002,25 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO //conn.bind(bindRequest); LDAPConnection conn = this.getReadWriteConnection(); - - PasswordModifyExtendedRequest passwordModifyRequest = - new PasswordModifyExtendedRequest( - userDN.toNormalizedString(), new String(oldPassword), new String(newPassword)); + PasswordModifyExtendedRequest passwordModifyRequest; + if (oldPassword == null) + { + passwordModifyRequest = + new PasswordModifyExtendedRequest(userDN.toNormalizedString(), + null, new String(newPassword)); + } + else + { + passwordModifyRequest = + new PasswordModifyExtendedRequest(userDN.toNormalizedString(), + new String(oldPassword), new String(newPassword)); + } PasswordModifyExtendedResult passwordModifyResult = (PasswordModifyExtendedResult) conn.processExtendedOperation(passwordModifyRequest); LdapDAO.checkLdapResult(passwordModifyResult.getResultCode()); + logger.debug("updatedPassword for " + userID.getName()); } catch (LDAPException e) { @@ -847,6 +1029,37 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO } } + /** + * Update a user's password. The given user and authenticating user must match. + * + * @param userID + * @param oldPassword current password. + * @param newPassword new password. + * @throws UserNotFoundException If the given user does not exist. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public void setPassword(HttpPrincipal userID, String oldPassword, String newPassword) + throws UserNotFoundException, TransientException, AccessControlException + { + updatePassword(userID, oldPassword, newPassword); + } + + /** + * Reset a user's password. The given user and authenticating user must match. + * + * @param userID + * @param newPassword new password. + * @throws UserNotFoundException If the given user does not exist. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public void resetPassword(HttpPrincipal userID, String newPassword) + throws UserNotFoundException, TransientException, AccessControlException + { + updatePassword(userID, null, newPassword); + } + /** * Delete the user specified by userID from the active user tree. * @@ -855,11 +1068,11 @@ 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 void deleteUser(final T userID) + public void deleteUser(final Principal userID, boolean markDelete) throws UserNotFoundException, TransientException, AccessControlException { - deleteUser(userID, config.getUsersDN(), true); + deleteUser(userID, config.getUsersDN(), markDelete); } /** @@ -870,29 +1083,27 @@ 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 void deletePendingUser(final T userID) + public void deleteUserRequest(final Principal userID) throws UserNotFoundException, TransientException, AccessControlException { deleteUser(userID, config.getUserRequestsDN(), false); } - private void deleteUser(final T userID, final String usersDN, boolean markDelete) + private void deleteUser(final Principal userID, final String usersDN, boolean markDelete) throws UserNotFoundException, AccessControlException, TransientException { - getUser(userID, usersDN); + User user2Delete = getUser(userID, usersDN); try { - DN userDN = getUserDN(userID.getName(), usersDN); + long uuid = uuid2long(user2Delete.getID().getUUID()); + DN userDN = getUserDN(uuid, usersDN); if (markDelete) { List<Modification> modifs = new ArrayList<Modification>(); modifs.add(new Modification(ModificationType.ADD, LDAP_NSACCOUNTLOCK, "true")); ModifyRequest modifyRequest = new ModifyRequest(userDN, modifs); - //modifyRequest.addControl( - // new ProxiedAuthorizationV2RequestControl( - // "dn:" + getSubjectDN().toNormalizedString())); LDAPResult result = getReadWriteConnection().modify(modifyRequest); LdapDAO.checkLdapResult(result.getResultCode()); @@ -900,13 +1111,12 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO else // real delete { DeleteRequest delRequest = new DeleteRequest(userDN); - //delRequest.addControl( - // new ProxiedAuthorizationV2RequestControl( - // "dn:" + getSubjectDN().toNormalizedString())); LDAPResult result = getReadWriteConnection().delete(delRequest); + logger.info("delete result:" + delRequest); LdapDAO.checkLdapResult(result.getResultCode()); } + logger.debug("deleted " + userID.getName() + " from " + usersDN); } catch (LDAPException e1) { @@ -927,75 +1137,53 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO } } - /** - * Returns a member user identified by the X500Principal only. The - * returned object has the fields required by the LdapGroupDAO. - * Note that this method binds as a proxy user and not as the - * subject. - * - * @param userDN - * @return - * @throws UserNotFoundException - * @throws LDAPException - */ - User<X500Principal> getX500User(DN userDN) - throws UserNotFoundException, LDAPException, TransientException + private Principal getPreferredPrincipal(User user) { - Filter filter = - Filter.createEqualityFilter(LDAP_ENTRYDN, - userDN.toNormalizedString()); - - SearchRequest searchRequest = - new SearchRequest(config.getUsersDN(), SearchScope.ONE, - filter, firstLastAttribs); - - SearchResultEntry searchResult = - getReadOnlyConnection().searchForEntry(searchRequest); - - if (searchResult == null) + Principal ret = null; + Principal next = null; + Iterator<Principal> i = user.getIdentities().iterator(); + while (i.hasNext()) { - String msg = "User not found " + userDN; - logger.debug(msg); - throw new UserNotFoundException(msg); + next = i.next(); + if (next instanceof NumericPrincipal) + { + return next; + } + ret = next; } - User<X500Principal> user = new User<X500Principal>( - new X500Principal(searchResult.getAttributeValue( - userLdapAttrib.get(X500Principal.class)))); - String princ = searchResult.getAttributeValue( - userLdapAttrib.get(HttpPrincipal.class)); - if (princ != null) + return ret; + } + + DN getUserDN(User user) + throws UserNotFoundException, TransientException, LDAPException + { + Principal p = getPreferredPrincipal(user); + if (p == null) { - user.getIdentities().add(new HttpPrincipal(princ)); + throw new UserNotFoundException("No identities"); } - String fname = searchResult.getAttributeValue(LDAP_FIRST_NAME); - String lname = searchResult.getAttributeValue(LDAP_LAST_NAME); - user.details.add(new PersonalDetails(fname, lname)); - return user; - } + // DN can be formulated if it is the numeric id + if (p instanceof NumericPrincipal) + return this.getUserDN(uuid2long(UUID.fromString(p.getName())), config.getUsersDN()); - DN getUserDN(User<? extends Principal> user) - throws UserNotFoundException, TransientException - { - String searchField = userLdapAttrib.get(user.getUserID().getClass()); + // Otherwise we need to search for the numeric id + String searchField = userLdapAttrib.get(p.getClass()); if (searchField == null) { throw new IllegalArgumentException( - "Unsupported principal type " + user.getUserID().getClass()); + "Unsupported principal type " + p.getClass()); } - // change the DN to be in the 'java' format - Filter filter; - if (user.getUserID() instanceof X500Principal) - { - X500Principal orderedPrincipal = AuthenticationUtil.getOrderedForm( - (X500Principal) user.getUserID()); - filter = Filter.createEqualityFilter(searchField, orderedPrincipal.toString()); - } - else - { - filter = Filter.createEqualityFilter(searchField, user.getUserID().getName()); - } +// change the DN to be in the 'java' format +// if (userID instanceof X500Principal) +// { +// X500Principal orderedPrincipal = AuthenticationUtil.getOrderedForm( +// (X500Principal) userID); +// filter = Filter.createEqualityFilter(searchField, orderedPrincipal.toString()); +// } + + Filter filter = Filter.createEqualityFilter(searchField, p.getName()); logger.debug("search filter: " + filter); SearchResultEntry searchResult = null; @@ -1004,6 +1192,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO SearchRequest searchRequest = new SearchRequest( config.getUsersDN(), SearchScope.ONE, filter, LDAP_ENTRYDN); searchResult = getReadOnlyConnection().searchForEntry(searchRequest); + logger.debug("getUserDN: got " + p.getName() + " from " + config.getUsersDN()); } catch (LDAPException e) { @@ -1012,26 +1201,17 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO if (searchResult == null) { - String msg = "User not found " + user.getUserID().getName(); + String msg = "User not found " + p.getName() + " in " + config.getUsersDN(); logger.debug(msg); throw new UserNotFoundException(msg); } return searchResult.getAttributeValueAsDN(LDAP_ENTRYDN); } - protected DN getUserDN(final String userID, final String usersDN) + protected DN getUserDN(long numericID, String usersDN) throws LDAPException, TransientException { - try - { - return new DN(LDAP_UID + "=" + userID + "," + usersDN); - } - catch (LDAPException e) - { - logger.debug("getUserDN Exception: " + e, e); - LdapDAO.checkLdapResult(e.getResultCode()); - } - throw new IllegalArgumentException(userID + " not a valid user ID"); + return new DN(LDAP_UID + "=" + numericID + "," + usersDN); } private void addAttribute(List<Attribute> attributes, final String name, final String value) @@ -1088,4 +1268,31 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO Random rand = new Random(); return rand.nextInt(Integer.MAX_VALUE - 10000) + 10000; } + + protected long uuid2long(UUID uuid) + { + return uuid.getLeastSignificantBits(); + } + + protected void setInternalIdUriPrefix(String internalIdUriPrefix) + { + this.internalIdUriPrefix = internalIdUriPrefix; + } + + protected InternalID getInternalID(String numericID) + { + UUID uuid = new UUID(0L, Long.parseLong(numericID)); + String uriString = internalIdUriPrefix + "?" + uuid.toString(); + URI uri; + try + { + uri = new URI(uriString); + } + catch (URISyntaxException e) + { + throw new RuntimeException("Invalid InternalID URI " + uriString); + } + return new InternalID(uri); + } + } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java index 11c2b20cc81306f3281e81180539b8eadccd150d..10b8448d7e7a6806f18be008dd9696b6faa4138c 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java @@ -72,6 +72,8 @@ import java.security.AccessControlException; import java.security.Principal; import java.util.Collection; +import javax.security.auth.Subject; + import org.apache.log4j.Logger; import ca.nrc.cadc.ac.User; @@ -85,13 +87,9 @@ import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.profiler.Profiler; -import com.unboundid.ldap.sdk.DN; -import javax.security.auth.Subject; - -public class LdapUserPersistence<T extends Principal> extends LdapPersistence implements UserPersistence<T> +public class LdapUserPersistence extends LdapPersistence implements UserPersistence { private static final Logger logger = Logger.getLogger(LdapUserPersistence.class); - private Profiler profiler = new Profiler(LdapUserPersistence.class); public LdapUserPersistence() { @@ -108,22 +106,22 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im } /** - * Add the user to the active users tree. + * Add the user to the users tree. * - * @param user The user request to put into the active user tree. + * @param user The user request to put into the user tree. * * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. * @throws ca.nrc.cadc.ac.UserAlreadyExistsException */ - public void addUser(UserRequest<T> user) + public void addUser(User user) throws TransientException, AccessControlException, UserAlreadyExistsException { - LdapUserDAO<T> userDAO = null; + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); + userDAO = getLdapUserDao(conns); userDAO.addUser(user); } finally @@ -133,23 +131,23 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im } /** - * Add the user to the pending users tree. + * Add the user to the user requests tree. * - * @param user The user request to put into the pending user tree. + * @param userRequest The user request to put into the pending user tree. * * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. * @throws ca.nrc.cadc.ac.UserAlreadyExistsException */ - public void addPendingUser(UserRequest<T> user) + public void addUserRequest(UserRequest userRequest) throws TransientException, AccessControlException, UserAlreadyExistsException { - LdapUserDAO<T> userDAO = null; + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); - userDAO.addPendingUser(user); + userDAO = getLdapUserDao(conns); + userDAO.addUserRequest(userRequest); } finally { @@ -168,18 +166,18 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public User<T> getUser(T userID) + public User getUser(Principal userID) throws UserNotFoundException, TransientException, AccessControlException { Subject caller = AuthenticationUtil.getCurrentSubject(); if ( !isMatch(caller, userID) ) throw new AccessControlException("permission denied: target user does not match current user"); - - LdapUserDAO<T> userDAO = null; + + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); + userDAO = getLdapUserDao(conns); return userDAO.getUser(userID); } finally @@ -188,6 +186,34 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im } } + /** + * Get the user specified by email address exists in the active users tree. + * + * @param emailAddress The user's email address. + * + * @return User ID. + * + * @throws UserNotFoundException when the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + * @throws UserAlreadyExistsException A user with the same email address already exists + */ + public User getUserByEmailAddress(String emailAddress) + throws UserNotFoundException, TransientException, + AccessControlException, UserAlreadyExistsException + { + LdapConnections conns = new LdapConnections(this); + try + { + LdapUserDAO userDAO = getLdapUserDao(conns); + return userDAO.getUserByEmailAddress(emailAddress); + } + finally + { + conns.releaseConnections(); + } + } + /** * Get the user specified by userID whose account is pending approval. * @@ -197,19 +223,19 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public User<T> getPendingUser(final T userID) + public User getUserRequest(Principal userID) throws UserNotFoundException, TransientException, AccessControlException { Subject caller = AuthenticationUtil.getCurrentSubject(); if ( !isMatch(caller, userID) ) throw new AccessControlException("permission denied: target user does not match current user"); - - LdapUserDAO<T> userDAO = null; + + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); - return userDAO.getPendingUser(userID); + userDAO = getLdapUserDao(conns); + return userDAO.getUserRequest(userID); } finally { @@ -217,7 +243,8 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im } } - /** + /**<<<<<<< HEAD + * Get the user specified by userID with all of the users identities. * * @param userID The userID. @@ -228,17 +255,18 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public User<T> getAugmentedUser(T userID) + public User getAugmentedUser(Principal userID) throws UserNotFoundException, TransientException { // internal call to return user identities: no permission check - LdapUserDAO<T> userDAO = null; + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); + Profiler profiler = new Profiler(LdapUserPersistence.class); + userDAO = getLdapUserDao(conns); profiler.checkpoint("Create LdapUserDAO"); - User<T> user = userDAO.getAugmentedUser(userID); + User user = userDAO.getAugmentedUser(userID); profiler.checkpoint("getAugmentedUser"); return user; } @@ -255,19 +283,23 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public Collection<User<Principal>> getUsers() + public Collection<User> getUsers() throws TransientException, AccessControlException { // current policy: usernames visible to all authenticated users Subject caller = AuthenticationUtil.getCurrentSubject(); if (caller == null || AuthMethod.ANON.equals(AuthenticationUtil.getAuthMethod(caller))) throw new AccessControlException("Caller is not authenticated"); - - LdapUserDAO<T> userDAO = null; + + // user must also have an approved account + if (caller.getPrincipals(HttpPrincipal.class).isEmpty()) + throw new AccessControlException("Caller does not have authorized account"); + + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); + userDAO = getLdapUserDao(conns); return userDAO.getUsers(); } finally @@ -277,22 +309,22 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im } /** - * Get all user names from the pending users tree. + * Get all user names from the user requests tree. * * @return A collection of strings. * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public Collection<User<Principal>> getPendingUsers() + public Collection<User> getUserRequests() throws TransientException, AccessControlException { // admin API: no permission check - LdapUserDAO<T> userDAO = null; + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); - return userDAO.getPendingUsers(); + userDAO = getLdapUserDao(conns); + return userDAO.getUserRequests(); } finally { @@ -301,8 +333,8 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im } /** - * Move the pending user specified by userID from the - * pending users tree to the active users tree. + * Move the user request specified by userID from the + * user requests tree to the users tree. * * @param userID The user instance to move. * @@ -312,17 +344,17 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public User<T> approvePendingUser(T userID) + public User approveUserRequest(Principal userID) throws UserNotFoundException, TransientException, AccessControlException { // admin API: no permission check - LdapUserDAO<T> userDAO = null; + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); - return userDAO.approvePendingUser(userID); + userDAO = getLdapUserDao(conns); + return userDAO.approveUserRequest(userID); } finally { @@ -341,19 +373,19 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public User<T> modifyUser(User<T> user) + public User modifyUser(User user) throws UserNotFoundException, TransientException, AccessControlException { Subject caller = AuthenticationUtil.getCurrentSubject(); if ( !isMatch(caller, user) ) throw new AccessControlException("permission denied: target user does not match current user"); - - LdapUserDAO<T> userDAO = null; + + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); + userDAO = getLdapUserDao(conns); return userDAO.modifyUser(user); } finally @@ -371,20 +403,49 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public void deleteUser(T userID) + public void deactivateUser(Principal userID) throws UserNotFoundException, TransientException, AccessControlException { Subject caller = AuthenticationUtil.getCurrentSubject(); if ( !isMatch(caller, userID) ) throw new AccessControlException("permission denied: target user does not match current user"); - - LdapUserDAO<T> userDAO = null; + + LdapUserDAO userDAO = null; + LdapConnections conns = new LdapConnections(this); + try + { + userDAO = getLdapUserDao(conns); + userDAO.deleteUser(userID, true); + } + finally + { + conns.releaseConnections(); + } + } + + /** + * 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(Principal userID) + throws UserNotFoundException, TransientException, + AccessControlException + { + + // admin API: permission checks done in action layer + // and in ACIs. + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); - userDAO.deleteUser(userID); + userDAO = getLdapUserDao(conns); + userDAO.deleteUser(userID, false); } finally { @@ -393,7 +454,7 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im } /** - * Delete the user specified by userID from the pending users tree. + * Delete the user specified by userID from the user requests tree. * * @param userID The userID. * @@ -401,17 +462,17 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public void deletePendingUser(T userID) + public void deleteUserRequest(Principal userID) throws UserNotFoundException, TransientException, AccessControlException { // admin API: no permission check - LdapUserDAO<T> userDAO = null; + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); - userDAO.deletePendingUser(userID); + userDAO = getLdapUserDao(conns); + userDAO.deleteUserRequest(userID); } finally { @@ -431,13 +492,13 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im * @throws AccessControlException If the operation is not permitted. */ public Boolean doLogin(String userID, String password) - throws UserNotFoundException, TransientException, AccessControlException + throws UserNotFoundException, TransientException, AccessControlException { - LdapUserDAO<T> userDAO = null; + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); + userDAO = getLdapUserDao(conns); return userDAO.doLogin(userID, password); } finally @@ -449,7 +510,11 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im /** * Update a user's password. The given user and authenticating user must match. * - * @param user +<<<<<<< HEAD + * @param userID the user. +======= + * @param userID +>>>>>>> efc84b5d25584bd3014fc6cbc820c5acf0d90a2a * @param oldPassword current password. * @param newPassword new password. * @throws UserNotFoundException If the given user does not exist. @@ -457,17 +522,17 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im * @throws AccessControlException If the operation is not permitted. */ public void setPassword(HttpPrincipal userID, String oldPassword, String newPassword) - throws UserNotFoundException, TransientException, AccessControlException + throws UserNotFoundException, TransientException, AccessControlException { Subject caller = AuthenticationUtil.getCurrentSubject(); if ( !isMatch(caller, userID) ) throw new AccessControlException("permission denied: target user does not match current user"); - - LdapUserDAO<T> userDAO = null; + + LdapUserDAO userDAO = null; LdapConnections conns = new LdapConnections(this); try { - userDAO = new LdapUserDAO<T>(conns); + userDAO = getLdapUserDao(conns); if (userDAO.doLogin(userID.getName(), oldPassword)) { // oldPassword is correct @@ -480,11 +545,50 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im } } - private boolean isMatch(Subject caller, User<T> user) + /** + * Reset a user's password. The given user and authenticating user must match. + * +<<<<<<< HEAD + * @param userID The user. +======= + * @param userID +>>>>>>> efc84b5d25584bd3014fc6cbc820c5acf0d90a2a + * @param newPassword new password. + * @throws UserNotFoundException If the given user does not exist. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public void resetPassword(HttpPrincipal userID, String newPassword) + throws UserNotFoundException, TransientException, AccessControlException + { + Subject caller = AuthenticationUtil.getCurrentSubject(); + if ( !isMatch(caller, userID) ) + throw new AccessControlException("permission denied: target user does not match current user"); + + LdapUserDAO userDAO = null; + LdapConnections conns = new LdapConnections(this); + try + { + userDAO = getLdapUserDao(conns); + User user = getUser(userID); + + if (user != null) + { + // oldPassword is correct + userDAO.resetPassword(userID, newPassword); + } + } + finally + { + conns.releaseConnections(); + } + } + + private boolean isMatch(Subject caller, User user) { if (caller == null || AuthMethod.ANON.equals(AuthenticationUtil.getAuthMethod(caller))) throw new AccessControlException("Caller is not authenticated"); - + for (Principal pc : caller.getPrincipals()) { for (Principal pu : user.getIdentities()) @@ -495,17 +599,37 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im } return false; } - - private boolean isMatch(Subject caller, Principal userID) + + private boolean isMatch(Subject caller, Principal identity) { if (caller == null || AuthMethod.ANON.equals(AuthenticationUtil.getAuthMethod(caller))) throw new AccessControlException("Caller is not authenticated"); - + for (Principal pc : caller.getPrincipals()) { - if (AuthenticationUtil.equals(pc, userID)) + if (AuthenticationUtil.equals(pc, identity)) return true; } return false; } + + private LdapUserDAO getLdapUserDao(LdapConnections conn) + { + LdapUserDAO dao = new LdapUserDAO(conn); + if (getInternalIdUriPrefix() != null) + dao.setInternalIdUriPrefix(getInternalIdUriPrefix()); + return dao; + } + + /** + * Web services can override this method to change + * the user prefix used in the internal ID. + * + * By default the LdapUserDAO will use AC.USER_URI; + */ + protected String getInternalIdUriPrefix() + { + return null; + } + } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java index ed53fbd7088208f427bf69163f05987a48950490..417d2e646ad94523d2753a97de14bf1bf74b4776 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java @@ -75,8 +75,6 @@ import ca.nrc.cadc.ac.server.GroupPersistence; import ca.nrc.cadc.ac.server.PluginFactory; import ca.nrc.cadc.ac.server.RequestValidator; import ca.nrc.cadc.ac.xml.GroupListWriter; -import ca.nrc.cadc.auth.AuthenticationUtil; -import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.uws.ExecutionPhase; import ca.nrc.cadc.uws.Job; @@ -87,7 +85,6 @@ import ca.nrc.cadc.uws.util.JobLogInfo; import org.apache.log4j.Logger; import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.OutputStream; @@ -221,9 +218,11 @@ public class ACSearchRunner implements JobRunner syncOut.setResponseCode(503); syncOut.setHeader("Content-Type", "text/plain"); + if (t.getRetryDelay() > 0) + syncOut.setHeader("Retry-After", Integer.toString(t.getRetryDelay())); try { - syncOut.getOutputStream().write(t.getMessage().getBytes()); + syncOut.getOutputStream().write(("Transient Exception: " + t.getMessage()).getBytes()); } catch (IOException e) { diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupServlet.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupServlet.java index 2111bcb0e7e2ee7b707cb4c7d1065189b0a45fc1..79fdb449c3236a78a1bca6c772d29bca3c49c6d4 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupServlet.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GroupServlet.java @@ -79,14 +79,13 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.log4j.Logger; + 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.ac.server.web.groups.AbstractGroupAction; import ca.nrc.cadc.ac.server.web.groups.GroupLogInfo; import ca.nrc.cadc.ac.server.web.groups.GroupsActionFactory; -import org.apache.log4j.Logger; - import ca.nrc.cadc.auth.AuthenticationUtil; /** @@ -94,14 +93,12 @@ import ca.nrc.cadc.auth.AuthenticationUtil; * * @author majorb */ -public class GroupServlet<T extends Principal> extends HttpServlet +public class GroupServlet extends HttpServlet { private static final long serialVersionUID = 7854660717655869213L; private static final Logger log = Logger.getLogger(GroupServlet.class); - public static final String GROUP_PERSISTENCE_REF = "groupPersistence"; - - private GroupPersistence<T> groupPersistence; + private GroupPersistence groupPersistence; @Override public void init(ServletConfig config) throws ServletException diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/LoginServlet.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/LoginServlet.java index 9bada3806a19fc92aedc22320927669f45a5b8b2..dd8722e84c616bcde1d934da9e50a1a1174a70e8 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/LoginServlet.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/LoginServlet.java @@ -69,10 +69,14 @@ package ca.nrc.cadc.ac.server.web; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.security.AccessControlException; import java.security.Principal; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.Calendar; +import java.util.GregorianCalendar; import javax.security.auth.Subject; import javax.servlet.ServletConfig; @@ -92,8 +96,10 @@ import ca.nrc.cadc.ac.server.PluginFactory; import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.ac.server.ldap.LdapGroupPersistence; import ca.nrc.cadc.auth.AuthenticatorImpl; +import ca.nrc.cadc.auth.DelegationToken; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.SSOCookieManager; +import ca.nrc.cadc.date.DateUtil; import ca.nrc.cadc.log.ServletLogInfo; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.util.StringUtil; @@ -101,20 +107,21 @@ import ca.nrc.cadc.util.StringUtil; import com.unboundid.ldap.sdk.LDAPException; @SuppressWarnings("serial") -public class LoginServlet<T extends Principal> extends HttpServlet +public class LoginServlet extends HttpServlet { private static final Logger log = Logger.getLogger(LoginServlet.class); + private static final String CONTENT_TYPE = "text/plain"; + private static final String PROXY_ACCESS = "Proxy user access: "; + // " as " - delimiter use for proxy user authentication public static final String PROXY_USER_DELIM = "\\s[aA][sS]\\s"; + String proxyGroup; // only users in this group can impersonate other users String nonImpersonGroup; // users in this group cannot be impersonated - private static final String PROXY_ACCESS = "Proxy user access: "; - - UserPersistence<T> userPersistence; - GroupPersistence<HttpPrincipal> groupPersistence; - + UserPersistence userPersistence; + GroupPersistence groupPersistence; @Override public void init(final ServletConfig config) throws ServletException @@ -138,6 +145,7 @@ public class LoginServlet<T extends Principal> extends HttpServlet throw new ExceptionInInitializerError(ex); } } + /** * Attempt to login for userid/password. */ @@ -152,6 +160,7 @@ public class LoginServlet<T extends Principal> extends HttpServlet log.info(logInfo.start()); String userID = request.getParameter("username"); String password = request.getParameter("password"); + String scope = request.getParameter("scope"); if (userID == null || userID.length() == 0) throw new IllegalArgumentException("Missing username"); @@ -174,9 +183,31 @@ public class LoginServlet<T extends Principal> extends HttpServlet (!StringUtil.hasText(proxyUser) && userPersistence.doLogin(userID, password))) { - String token = - new SSOCookieManager().generate( - new HttpPrincipal(userID, proxyUser)); + String token = null; + HttpPrincipal p = new HttpPrincipal(userID, proxyUser); + if (scope != null) + { + // This cookie will be scope to a certain URI, + // such as a VOSpace node + URI uri = null; + try + { + uri = new URI(scope); + } + catch (URISyntaxException e) + { + throw new IllegalArgumentException("Invalid scope: " + scope); + } + + final Calendar expiryDate = new GregorianCalendar(DateUtil.UTC); + expiryDate.add(Calendar.HOUR, SSOCookieManager.SSO_COOKIE_LIFETIME_HOURS); + DelegationToken dt = new DelegationToken(p, uri, expiryDate.getTime()); + token = DelegationToken.format(dt); + } + else + { + token = new SSOCookieManager().generate(p); + } response.setContentType(CONTENT_TYPE); response.setContentLength(token.length()); response.getWriter().write(token); @@ -208,6 +239,18 @@ public class LoginServlet<T extends Principal> extends HttpServlet response.getWriter().write(message); response.setStatus(401); } + catch (TransientException e) + { + log.debug(e.getMessage(), e); + String message = e.getMessage(); + logInfo.setMessage(message); + logInfo.setSuccess(false); + response.setContentType("CONTENT_TYPE"); + if (e.getRetryDelay() > 0) + response.setHeader("Retry-After", Integer.toString(e.getRetryDelay())); + response.getWriter().write("Transient Error: " + message); + response.setStatus(503); + } catch (Throwable t) { String message = "Internal Server Error: " + t.getMessage(); @@ -297,9 +340,9 @@ public class LoginServlet<T extends Principal> extends HttpServlet } } - protected LdapGroupPersistence<HttpPrincipal> getLdapGroupPersistence() throws AccessControlException, LDAPException + protected LdapGroupPersistence getLdapGroupPersistence() throws AccessControlException, LDAPException { - LdapGroupPersistence<HttpPrincipal> gp = new LdapGroupPersistence<HttpPrincipal>(); + LdapGroupPersistence gp = new LdapGroupPersistence(); gp.setDetailSelector(new GroupDetailSelector() { @Override diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/PasswordServlet.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyPasswordServlet.java similarity index 74% rename from cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/PasswordServlet.java rename to cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyPasswordServlet.java index adbca8c63213aabee5f6f83959ff8cbd94e87c30..90d54ebbe421db5bd8d42296e399156601eed8b2 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/PasswordServlet.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyPasswordServlet.java @@ -68,13 +68,11 @@ */ package ca.nrc.cadc.ac.server.web; -import ca.nrc.cadc.ac.server.PluginFactory; -import ca.nrc.cadc.ac.server.UserPersistence; -import ca.nrc.cadc.auth.AuthenticationUtil; -import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.log.ServletLogInfo; -import ca.nrc.cadc.util.StringUtil; -import org.apache.log4j.Logger; +import java.io.IOException; +import java.security.AccessControlException; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Set; import javax.security.auth.Subject; import javax.servlet.ServletConfig; @@ -82,10 +80,16 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.security.AccessControlException; -import java.security.PrivilegedExceptionAction; -import java.util.Set; + +import org.apache.log4j.Logger; + +import ca.nrc.cadc.ac.server.PluginFactory; +import ca.nrc.cadc.ac.server.UserPersistence; +import ca.nrc.cadc.auth.AuthenticationUtil; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.log.ServletLogInfo; +import ca.nrc.cadc.net.TransientException; +import ca.nrc.cadc.util.StringUtil; /** * Servlet to handle password changes. Passwords are an integral part of the @@ -95,9 +99,9 @@ import java.util.Set; * This servlet handles POST only. It relies on the Subject being set higher * up by the AccessControlFilter as configured in the web descriptor. */ -public class PasswordServlet extends HttpServlet +public class ModifyPasswordServlet extends HttpServlet { - private static final Logger log = Logger.getLogger(PasswordServlet.class); + private static final Logger log = Logger.getLogger(ModifyPasswordServlet.class); UserPersistence userPersistence; @@ -126,12 +130,11 @@ public class PasswordServlet extends HttpServlet log.info(logInfo.start()); try { - final Subject subject = AuthenticationUtil.getSubject(request); + final Subject subject = getSubject(request); logInfo.setSubject(subject); if ((subject == null) || (subject.getPrincipals().isEmpty())) { - logInfo.setMessage("Unauthorized subject"); - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + throw new AccessControlException("Unauthorized"); } else { @@ -139,7 +142,7 @@ public class PasswordServlet extends HttpServlet { public Object run() throws Exception { - + Set<HttpPrincipal> pset = subject.getPrincipals(HttpPrincipal.class); if (pset.isEmpty()) throw new IllegalStateException("no HttpPrincipal in subject"); @@ -167,30 +170,72 @@ public class PasswordServlet extends HttpServlet }); } } - catch (IllegalArgumentException e) - { - log.debug(e.getMessage(), e); - logInfo.setMessage(e.getMessage()); - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - } - catch (AccessControlException e) - { - log.debug(e.getMessage(), e); - logInfo.setMessage(e.getMessage()); - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - } catch (Throwable t) { - String message = "Internal Server Error: " + t.getMessage(); - log.error(message, t); - logInfo.setSuccess(false); - logInfo.setMessage(message); - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - finally - { - logInfo.setElapsedTime(System.currentTimeMillis() - start); - log.info(logInfo.end()); + try + { + if (t instanceof PrivilegedActionException) + { + Exception e = ((PrivilegedActionException) t).getException(); + if (e != null) + { + throw e; + } + } + + throw t; + } + catch (IllegalArgumentException e) + { + log.debug(e.getMessage(), e); + response.setContentType("text/plain"); + logInfo.setMessage(e.getMessage()); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + catch (AccessControlException e) + { + log.debug(e.getMessage(), e); + response.setContentType("text/plain"); + logInfo.setMessage(e.getMessage()); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + catch (TransientException e) + { + log.debug(e.getMessage(), e); + String message = e.getMessage(); + logInfo.setMessage(message); + logInfo.setSuccess(false); + response.setContentType("text/plain"); + if (e.getRetryDelay() > 0) + response.setHeader("Retry-After", Integer.toString(e.getRetryDelay())); + response.getWriter().write("Transient Error: " + message); + response.setStatus(503); + } + catch (Throwable e) + { + String message = "Internal Server Error: " + e.getMessage(); + log.error(message, e); + response.setContentType("text/plain"); + logInfo.setSuccess(false); + logInfo.setMessage(message); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + finally + { + logInfo.setElapsedTime(System.currentTimeMillis() - start); + log.info(logInfo.end()); + } } } + + /** + * Get and augment the Subject. Tests can override this method. + * + * @param request Servlet request + * @return augmented Subject + */ + Subject getSubject(final HttpServletRequest request) + { + return AuthenticationUtil.getSubject(request); + } } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ResetPasswordServlet.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ResetPasswordServlet.java new file mode 100644 index 0000000000000000000000000000000000000000..2d261a1993c6d04979064d95a4895d9d48d624f8 --- /dev/null +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ResetPasswordServlet.java @@ -0,0 +1,457 @@ +/* + ************************************************************************ + ******************* 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; + +import java.io.IOException; +import java.net.URI; +import java.security.AccessControlException; +import java.security.Principal; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.Set; +import java.util.TimeZone; + +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; + +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserAlreadyExistsException; +import ca.nrc.cadc.ac.UserNotFoundException; +import ca.nrc.cadc.ac.server.ACScopeValidator; +import ca.nrc.cadc.ac.server.PluginFactory; +import ca.nrc.cadc.ac.server.UserPersistence; +import ca.nrc.cadc.auth.AuthenticationUtil; +import ca.nrc.cadc.auth.DelegationToken; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.auth.ServletPrincipalExtractor; +import ca.nrc.cadc.log.ServletLogInfo; +import ca.nrc.cadc.net.TransientException; +import ca.nrc.cadc.util.StringUtil; + +/** + * Servlet to handle password resets. Passwords are an integral part of the + * access control system and are handled differently to accommodate stricter + * guidelines. + * <p/> + * This servlet handles GET and POST only. It relies on the Subject being set higher + * up by the AccessControlFilter as configured in the web descriptor. + */ +public class ResetPasswordServlet extends HttpServlet +{ + private static final Logger log = Logger.getLogger(ResetPasswordServlet.class); + + List<Subject> privilegedSubjects; + UserPersistence userPersistence; + + @Override + public void init(final ServletConfig config) throws ServletException + { + super.init(config); + + try + { + String x500Users = config.getInitParameter(ResetPasswordServlet.class.getName() + ".PrivilegedX500Principals"); + log.debug("privilegedX500Users: " + x500Users); + + String httpUsers = config.getInitParameter(ResetPasswordServlet.class.getName() + ".PrivilegedHttpPrincipals"); + log.debug("privilegedHttpUsers: " + httpUsers); + + String[] x500List = new String[0]; + String[] httpList = new String[0]; + if (x500Users != null && httpUsers != null) + { + x500List = x500Users.split(" "); + httpList = httpUsers.split(" "); + + if (x500List.length != httpList.length) + { + throw new RuntimeException("Init exception: Lists of augment subject principals not equivalent in length"); + } + + privilegedSubjects = new ArrayList<Subject>(x500Users.length()); + for (int i=0; i<x500List.length; i++) + { + Subject s = new Subject(); + s.getPrincipals().add(new X500Principal(x500List[i])); + s.getPrincipals().add(new HttpPrincipal(httpList[i])); + privilegedSubjects.add(s); + } + } + + PluginFactory pluginFactory = new PluginFactory(); + userPersistence = pluginFactory.createUserPersistence(); + } + catch (Throwable t) + { + log.fatal("Error initializing group persistence", t); + throw new ExceptionInInitializerError(t); + } + } + + protected boolean isPrivilegedSubject(final HttpServletRequest request) + { + if (privilegedSubjects == null || privilegedSubjects.isEmpty()) + { + return false; + } + + ServletPrincipalExtractor extractor = new ServletPrincipalExtractor(request); + Set<Principal> principals = extractor.getPrincipals(); + + for (Principal principal : principals) + { + if (principal instanceof X500Principal) + { + for (Subject s : privilegedSubjects) + { + Set<X500Principal> x500Principals = s.getPrincipals(X500Principal.class); + for (X500Principal p2 : x500Principals) + { + if (p2.getName().equalsIgnoreCase(principal.getName())) + { + return true; + } + } + } + } + + if (principal instanceof HttpPrincipal) + { + for (Subject s : privilegedSubjects) + { + Set<HttpPrincipal> httpPrincipals = s.getPrincipals(HttpPrincipal.class); + for (HttpPrincipal p2 : httpPrincipals) + { + if (p2.getName().equalsIgnoreCase(principal.getName())) + { + return true; + } + } + } + } + } + + return false; + } + + /** + * Handle a /ac GET operation. The subject provided is expected to be a privileged user. + * + * @param request The HTTP Request. + * @param response The HTTP Response. + * @throws ServletException Anything goes wrong at the Servlet level. + * @throws IOException Any reading/writing errors. + */ + @Override + protected void doGet(final HttpServletRequest request, + final HttpServletResponse response) + throws ServletException, IOException + { + final long start = System.currentTimeMillis(); + final ServletLogInfo logInfo = new ServletLogInfo(request); + log.info(logInfo.start()); + try + { + final Subject subject = getSubject(request); + logInfo.setSubject(subject); + if ((subject == null) || (subject.getPrincipals().isEmpty())) + { + logInfo.setMessage("Unauthorized subject"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + else + { + if (isPrivilegedSubject(request)) + { + String token = (String) Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + String emailAddress = request.getParameter("emailAddress"); + if (StringUtil.hasText(emailAddress)) + { + User user = userPersistence.getUserByEmailAddress(emailAddress); + HttpPrincipal userID = (HttpPrincipal) user.getHttpPrincipal(); + URI scopeURI = new URI(ACScopeValidator.RESET_PASSWORD_SCOPE); + int duration = 24; // hours + Calendar expiry = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + expiry.add(Calendar.HOUR, duration); + DelegationToken dt = new DelegationToken(userID, scopeURI, expiry.getTime()); + + return DelegationToken.format(dt); + } + else + { + throw new IllegalArgumentException("Missing email address"); + } + } + }); + + response.setContentType("text/plain"); + response.setContentLength(token.length()); + response.getWriter().write(token); + } + else + { + logInfo.setMessage("Permission denied subject"); + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + } + } + } + catch (Throwable t) + { + try + { + if (t instanceof PrivilegedActionException) + { + Exception e = ((PrivilegedActionException) t).getException(); + if (e != null) + { + throw e; + } + } + + throw t; + } + catch (UserAlreadyExistsException e) + { + log.debug(e.getMessage(), e); + logInfo.setMessage(e.getMessage()); + response.setStatus(HttpServletResponse.SC_CONFLICT); + } + catch (UserNotFoundException e) + { + log.debug(e.getMessage(), e); + logInfo.setMessage(e.getMessage()); + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + catch (IllegalArgumentException e) + { + log.debug(e.getMessage(), e); + logInfo.setMessage(e.getMessage()); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + catch (TransientException e) + { + log.debug(e.getMessage(), e); + String message = e.getMessage(); + logInfo.setMessage(message); + logInfo.setSuccess(false); + response.setContentType("text/plain"); + if (e.getRetryDelay() > 0) + response.setHeader("Retry-After", Integer.toString(e.getRetryDelay())); + response.getWriter().write("Transient Error: " + message); + response.setStatus(503); + } + catch (AccessControlException e) + { + log.debug(e.getMessage(), e); + logInfo.setMessage(e.getMessage()); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + catch (Throwable t1) + { + String message = "Internal Server Error: " + t.getMessage(); + log.error(message, t); + logInfo.setSuccess(false); + logInfo.setMessage(message); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } + finally + { + logInfo.setElapsedTime(System.currentTimeMillis() - start); + log.info(logInfo.end()); + } + } + + /** + * Attempt to change password. + * + * @param request The HTTP Request. + * @param response The HTTP Response. + * @throws IOException Any errors that are not expected. + */ + public void doPost(final HttpServletRequest request, + final HttpServletResponse response) + throws IOException + { + final long start = System.currentTimeMillis(); + final ServletLogInfo logInfo = new ServletLogInfo(request); + log.info(logInfo.start()); + try + { + final Subject subject = getSubject(request); + logInfo.setSubject(subject); + if ((subject == null) || (subject.getPrincipals().isEmpty())) + { + logInfo.setMessage("Unauthorized subject"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + else + { + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + + Set<HttpPrincipal> pset = subject.getPrincipals(HttpPrincipal.class); + if (pset.isEmpty()) + { + throw new IllegalStateException("no HttpPrincipal in subject"); + } + + HttpPrincipal userID = pset.iterator().next(); + + String newPassword = request.getParameter("password"); + if (StringUtil.hasText(newPassword)) + { + userPersistence.resetPassword(userID, newPassword); + } + else + { + throw new IllegalArgumentException("Missing password"); + } + + return null; + } + }); + } + } + catch (Throwable t) + { + try + { + if (t instanceof PrivilegedActionException) + { + Exception e = ((PrivilegedActionException) t).getException(); + if (e != null) + { + throw e; + } + } + + throw t; + } + catch (UserNotFoundException e) + { + log.debug(e.getMessage(), e); + logInfo.setMessage(e.getMessage()); + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + catch (IllegalArgumentException e) + { + log.debug(e.getMessage(), e); + logInfo.setMessage(e.getMessage()); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + catch (AccessControlException e) + { + log.debug(e.getMessage(), e); + logInfo.setMessage(e.getMessage()); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + catch (Throwable t1) + { + String message = "Internal Server Error: " + t.getMessage(); + log.error(message, t); + logInfo.setSuccess(false); + logInfo.setMessage(message); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } + finally + { + logInfo.setElapsedTime(System.currentTimeMillis() - start); + log.info(logInfo.end()); + } + } + + /** + * Get and augment the Subject. Tests can override this method. + * + * @param request Servlet request + * @return augmented Subject + */ + Subject getSubject(final HttpServletRequest request) + { + return AuthenticationUtil.getSubject(request); + } +} diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/UserRequestServlet.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/UserRequestServlet.java new file mode 100644 index 0000000000000000000000000000000000000000..7b938b3b8791ff77e7f23a26da8852548a69dfb2 --- /dev/null +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/UserRequestServlet.java @@ -0,0 +1,359 @@ +/* + ************************************************************************ + ******************* 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/>. + * + * $Revision: 4 $ + * + ************************************************************************ + */ +package ca.nrc.cadc.ac.server.web; + +import java.io.IOException; +import java.security.AccessController; +import java.security.Principal; +import java.security.PrivilegedActionException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; + +import ca.nrc.cadc.ac.server.PluginFactory; +import ca.nrc.cadc.ac.server.UserPersistence; +import ca.nrc.cadc.ac.server.web.userrequests.AbstractUserRequestAction; +import ca.nrc.cadc.ac.server.web.userrequests.CreateUserRequestAction; +import ca.nrc.cadc.ac.server.web.userrequests.UserRequestActionFactory; +import ca.nrc.cadc.ac.server.web.users.AbstractUserAction; +import ca.nrc.cadc.ac.server.web.users.UserLogInfo; +import ca.nrc.cadc.auth.AuthenticationUtil; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.auth.ServletPrincipalExtractor; +import ca.nrc.cadc.profiler.Profiler; +import ca.nrc.cadc.util.StringUtil; + +public class UserRequestServlet extends HttpServlet +{ + private static final long serialVersionUID = 6290241995918416399L; + private static final Logger log = Logger.getLogger(UserRequestServlet.class); + + private List<Subject> privilegedSubjects; + + private UserPersistence userPersistence; + + @Override + public void init(ServletConfig config) throws ServletException + { + super.init(config); + + try + { + String x500Users = config.getInitParameter(UserRequestServlet.class.getName() + ".PrivilegedX500Principals"); + log.debug("PrivilegedX500Users: " + x500Users); + + String httpUsers = config.getInitParameter(UserRequestServlet.class.getName() + ".PrivilegedHttpPrincipals"); + log.debug("PrivilegedHttpUsers: " + httpUsers); + + String[] x500List = new String[0]; + String[] httpList = new String[0]; + if (x500Users != null && httpUsers != null) + { + x500List = x500Users.split(" "); + httpList = httpUsers.split(" "); + + if (x500List.length != httpList.length) + { + throw new RuntimeException("Init exception: Lists of augment subject principals not equivalent in length"); + } + + privilegedSubjects = new ArrayList<Subject>(x500Users.length()); + for (int i = 0; i < x500List.length; i++) + { + Subject s = new Subject(); + s.getPrincipals().add(new X500Principal(x500List[i])); + s.getPrincipals().add(new HttpPrincipal(httpList[i])); + privilegedSubjects.add(s); + } + } + else + { + log.warn("No Privileged users configured."); + } + + PluginFactory pluginFactory = new PluginFactory(); + userPersistence = pluginFactory.createUserPersistence(); + } + catch (Throwable t) + { + log.fatal("Error initializing group persistence", t); + throw new ExceptionInInitializerError(t); + } + } + + /** + * Create a UserAction and run the action safely. + */ + private void doAction(UserRequestActionFactory factory, HttpServletRequest request, HttpServletResponse response) + throws IOException + { + Profiler profiler = new Profiler(UserRequestServlet.class); + long start = System.currentTimeMillis(); + UserLogInfo logInfo = new UserLogInfo(request); + + try + { + log.info(logInfo.start()); + AbstractUserRequestAction action = factory.createAction(request); + action.setAcceptedContentType(getAcceptedContentType(request)); + log.debug("content-type: " + getAcceptedContentType(request)); + profiler.checkpoint("created action"); + + // Special case: if the calling subject has a privileged X500Principal, + // AND it is a PUT request, do not augment the subject. + Subject subject; + Subject privilegedSubject = getPrivilegedSubject(request); + if (action instanceof CreateUserRequestAction && privilegedSubject != null) + { + profiler.checkpoint("check privileged user"); + subject = Subject.getSubject(AccessController.getContext()); + log.debug("subject not augmented: " + subject); + action.setAugmentUser(true); + logInfo.setSubject(privilegedSubject); + profiler.checkpoint("set privileged user"); + } + else + { + subject = AuthenticationUtil.getSubject(request); + logInfo.setSubject(subject); + log.debug("augmented subject: " + subject); + profiler.checkpoint("augment subject"); + } + + SyncOutput syncOut = new SyncOutput(response); + action.setLogInfo(logInfo); + action.setSyncOut(syncOut); + action.setUserPersistence(userPersistence); + + try + { + if (subject == null) + { + action.run(); + } + else + { + Subject.doAs(subject, action); + } + } + catch (PrivilegedActionException e) + { + Throwable cause = e.getCause(); + if (cause != null) + { + throw cause; + } + Exception exception = e.getException(); + if (exception != null) + { + throw exception; + } + throw e; + } + finally + { + profiler.checkpoint("Executed action"); + } + } + catch (IllegalArgumentException e) + { + log.debug(e.getMessage(), e); + logInfo.setMessage(e.getMessage()); + logInfo.setSuccess(false); + response.getWriter().write(e.getMessage()); + response.setStatus(400); + } + catch (Throwable t) + { + String message = "Internal Server Error: " + t.getMessage(); + log.error(message, t); + logInfo.setSuccess(false); + logInfo.setMessage(message); + response.getWriter().write(message); + response.setStatus(500); + } + finally + { + logInfo.setElapsedTime(System.currentTimeMillis() - start); + log.info(logInfo.end()); + } + } + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException + { + doAction(UserRequestActionFactory.httpGetFactory(), request, response); + } + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws IOException + { + doAction(UserRequestActionFactory.httpPostFactory(), request, response); + } + + @Override + public void doDelete(HttpServletRequest request, HttpServletResponse response) + throws IOException + { + doAction(UserRequestActionFactory.httpDeleteFactory(), request, response); + } + + @Override + public void doPut(HttpServletRequest request, HttpServletResponse response) + throws IOException + { + doAction(UserRequestActionFactory.httpPutFactory(), request, response); + } + + @Override + public void doHead(HttpServletRequest request, HttpServletResponse response) + throws IOException + { + doAction(UserRequestActionFactory.httpHeadFactory(), request, response); + } + + /** + * Obtain the requested (Accept) content type. + * + * @param request The HTTP Request. + * @return String content type. + */ + String getAcceptedContentType(final HttpServletRequest request) + { + final String requestedContentType = request.getHeader("Accept"); + + if (StringUtil.hasText(requestedContentType) + && requestedContentType.contains(AbstractUserAction.JSON_CONTENT_TYPE)) + { + return AbstractUserAction.JSON_CONTENT_TYPE; + } + else + { + return AbstractUserAction.DEFAULT_CONTENT_TYPE; + } + } + + protected Subject getPrivilegedSubject(HttpServletRequest request) + { + if (privilegedSubjects == null || privilegedSubjects.isEmpty()) + { + return null; + } + + ServletPrincipalExtractor extractor = new ServletPrincipalExtractor(request); + Set<Principal> principals = extractor.getPrincipals(); + + for (Principal principal : principals) + { + if (principal instanceof X500Principal) + { + for (Subject s : privilegedSubjects) + { + Set<X500Principal> x500Principals = s.getPrincipals(X500Principal.class); + for (X500Principal p2 : x500Principals) + { + if (p2.getName().equalsIgnoreCase(principal.getName())) + { + return s; + } + } + } + } + + if (principal instanceof HttpPrincipal) + { + for (Subject s : privilegedSubjects) + { + Set<HttpPrincipal> httpPrincipals = s.getPrincipals(HttpPrincipal.class); + for (HttpPrincipal p2 : httpPrincipals) + { + if (p2.getName().equalsIgnoreCase(principal.getName())) + { + return s; + } + } + } + } + } + + return null; + } +} diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/UserServlet.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/UserServlet.java index e1050d48ad1720077e0842af34299a5cbd8b4083..ef27f7424ef9d255a4fa20f44335dc1371414774 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/UserServlet.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/UserServlet.java @@ -89,6 +89,7 @@ import org.apache.log4j.Logger; import ca.nrc.cadc.ac.server.PluginFactory; import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.ac.server.web.users.AbstractUserAction; +import ca.nrc.cadc.ac.server.web.users.CreateUserAction; import ca.nrc.cadc.ac.server.web.users.GetUserAction; import ca.nrc.cadc.ac.server.web.users.UserActionFactory; import ca.nrc.cadc.ac.server.web.users.UserLogInfo; @@ -98,17 +99,14 @@ import ca.nrc.cadc.auth.ServletPrincipalExtractor; import ca.nrc.cadc.profiler.Profiler; import ca.nrc.cadc.util.StringUtil; -public class UserServlet<T extends Principal> extends HttpServlet +public class UserServlet extends HttpServlet { - private static final long serialVersionUID = 5289130885807305288L; private static final Logger log = Logger.getLogger(UserServlet.class); - public static final String USER_PERSISTENCE_REF = "userPersistence"; - - private List<Subject> notAugmentedSubjects; + private List<Subject> privilegedSubjects; - private UserPersistence<T> userPersistence; + private UserPersistence userPersistence; @Override public void init(ServletConfig config) throws ServletException @@ -117,11 +115,11 @@ public class UserServlet<T extends Principal> extends HttpServlet try { - String x500Users = config.getInitParameter(UserServlet.class.getName() + ".NotAugmentedX500Principals"); - log.debug("notAugmentedX500Users: " + x500Users); + String x500Users = config.getInitParameter(UserServlet.class.getName() + ".PrivilegedX500Principals"); + log.debug("PrivilegedX500Users: " + x500Users); - String httpUsers = config.getInitParameter(UserServlet.class.getName() + ".NotAugmentedHttpPrincipals"); - log.debug("notAugmentedHttpUsers: " + httpUsers); + String httpUsers = config.getInitParameter(UserServlet.class.getName() + ".PrivilegedHttpPrincipals"); + log.debug("PrivilegedHttpUsers: " + httpUsers); String[] x500List = new String[0]; String[] httpList = new String[0]; @@ -129,20 +127,25 @@ public class UserServlet<T extends Principal> extends HttpServlet { x500List = x500Users.split(" "); httpList = httpUsers.split(" "); - } - if (x500List.length != httpList.length) - { - throw new RuntimeException("Init exception: Lists of augment subject principals not equivalent in length"); - } + if (x500List.length != httpList.length) + { + throw new RuntimeException("Init exception: Lists of augment subject principals not equivalent in length"); + } - notAugmentedSubjects = new ArrayList<Subject>(x500Users.length()); - for (int i=0; i<x500List.length; i++) + privilegedSubjects = new ArrayList<Subject>(x500Users.length()); + for (int i=0; i<x500List.length; i++) + { + Subject s = new Subject(); + s.getPrincipals().add(new X500Principal(x500List[i])); + s.getPrincipals().add(new HttpPrincipal(httpList[i])); + privilegedSubjects.add(s); + } + + } + else { - Subject s = new Subject(); - s.getPrincipals().add(new X500Principal(x500List[i])); - s.getPrincipals().add(new HttpPrincipal(httpList[i])); - notAugmentedSubjects.add(s); + log.warn("No Privileged users configured."); } PluginFactory pluginFactory = new PluginFactory(); @@ -175,22 +178,54 @@ public class UserServlet<T extends Principal> extends HttpServlet { log.info(logInfo.start()); AbstractUserAction action = factory.createAction(request); + log.debug("create action " + action.getClass().getSimpleName()); action.setAcceptedContentType(getAcceptedContentType(request)); log.debug("content-type: " + getAcceptedContentType(request)); - profiler.checkpoint("created action"); +// profiler.checkpoint("created action"); - // Special case: if the calling subject has a servops X500Principal, - // AND it is a GET request, do not augment the subject. Subject subject; - Subject notAugmentedSubject = getNotAugmentedSubject(request); - if (action instanceof GetUserAction && notAugmentedSubject != null) + Subject privilegedSubject = getPrivilegedSubject(request); + log.debug("privileged subject: " + privilegedSubject); + if (privilegedSubject != null) + { + action.setIsPrivilegedUser(true); + action.setPrivilegedSubject(true); + logInfo.setSubject(privilegedSubject); + } + else + { + action.setIsPrivilegedUser(false); + action.setPrivilegedSubject(false); + } + + // If the calling subject is not a PrivilegedSubject, + // AND it is a PUT request, throw an AccessControlException + if (action instanceof CreateUserAction) + { + profiler.checkpoint("check non-privileged user"); + if (privilegedSubject == null) + { + subject = AuthenticationUtil.getSubject(request); + logInfo.setSubject(subject); + log.debug("augmented subject: " + subject); + profiler.checkpoint("augment subject"); + } + else + { + log.debug("subject not augmented: " + privilegedSubject); + subject = privilegedSubject; + logInfo.setSubject(privilegedSubject); + profiler.checkpoint("set privileged user"); + } + } + + // If the calling subject has a privileged X500Principal, + // AND it is a GET request, do not augment the subject. + else if (action instanceof GetUserAction && privilegedSubject != null) { - profiler.checkpoint("check not augmented user"); subject = Subject.getSubject(AccessController.getContext()); log.debug("subject not augmented: " + subject); - action.setAugmentUser(true); - logInfo.setSubject(notAugmentedSubject); - profiler.checkpoint("set not augmented user"); + profiler.checkpoint("set privileged user"); } else { @@ -254,6 +289,7 @@ public class UserServlet<T extends Principal> extends HttpServlet } finally { + profiler.checkpoint("Action complete"); logInfo.setElapsedTime(System.currentTimeMillis() - start); log.info(logInfo.end()); } @@ -315,9 +351,9 @@ public class UserServlet<T extends Principal> extends HttpServlet } } - protected Subject getNotAugmentedSubject(HttpServletRequest request) + protected Subject getPrivilegedSubject(HttpServletRequest request) { - if (notAugmentedSubjects == null || notAugmentedSubjects.isEmpty()) + if (privilegedSubjects == null || privilegedSubjects.isEmpty()) { return null; } @@ -329,7 +365,7 @@ public class UserServlet<T extends Principal> extends HttpServlet { if (principal instanceof X500Principal) { - for (Subject s : notAugmentedSubjects) + for (Subject s : privilegedSubjects) { Set<X500Principal> x500Principals = s.getPrincipals(X500Principal.class); for (X500Principal p2 : x500Principals) @@ -344,7 +380,7 @@ public class UserServlet<T extends Principal> extends HttpServlet if (principal instanceof HttpPrincipal) { - for (Subject s : notAugmentedSubjects) + for (Subject s : privilegedSubjects) { Set<HttpPrincipal> httpPrincipals = s.getPrincipals(HttpPrincipal.class); for (HttpPrincipal p2 : httpPrincipals) diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/WhoAmIServlet.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/WhoAmIServlet.java index 0a06a9bbc685a9a74bd2d07cc050ef4d327f7e73..e97e1165c0f34c114fc119e6df08063d854beba8 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/WhoAmIServlet.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/WhoAmIServlet.java @@ -68,22 +68,24 @@ package ca.nrc.cadc.ac.server.web; -import ca.nrc.cadc.ac.AC; -import ca.nrc.cadc.auth.AuthenticationUtil; -import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.log.ServletLogInfo; -import ca.nrc.cadc.reg.client.RegistryClient; -import org.apache.log4j.Logger; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.util.Set; import javax.security.auth.Subject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.net.URI; -import java.net.URL; -import java.util.Set; + +import org.apache.log4j.Logger; + +import ca.nrc.cadc.ac.AC; +import ca.nrc.cadc.auth.AuthenticationUtil; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.log.ServletLogInfo; +import ca.nrc.cadc.reg.client.RegistryClient; /** * Servlet to handle GET requests asking for the current User. This servlet @@ -95,7 +97,7 @@ public class WhoAmIServlet extends HttpServlet { private static final Logger log = Logger.getLogger(WhoAmIServlet.class); - static final String USER_GET_PATH = "/users/%s?idType=HTTP"; + static final String USER_GET_PATH = "/%s?idType=HTTP"; /** * Handle a /whoami GET operation. @@ -158,13 +160,13 @@ public class WhoAmIServlet extends HttpServlet * @param scheme The scheme */ void redirect(final HttpServletResponse response, - final HttpPrincipal webPrincipal, + final HttpPrincipal webPrincipal, final String scheme) throws IOException { final RegistryClient registryClient = getRegistryClient(); final URL redirectURL = registryClient.getServiceURL( - URI.create(AC.GMS_SERVICE_URI), scheme, USER_GET_PATH); + URI.create(AC.UMS_SERVICE_URI + "#users"), scheme, USER_GET_PATH); // Take the first one. final String redirectUrl = diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AbstractGroupAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AbstractGroupAction.java index 8a95d1f47ed8bbe71400a8124ba22c7dcba73c95..b71d3262299d7cc059ce0619e5cf5bc96a29fd96 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AbstractGroupAction.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AbstractGroupAction.java @@ -68,27 +68,29 @@ */ package ca.nrc.cadc.ac.server.web.groups; +import java.io.IOException; +import java.security.AccessControlException; +import java.security.Principal; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Iterator; +import java.util.List; + +import javax.security.auth.x500.X500Principal; +import javax.servlet.http.HttpServletRequest; + +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.User; 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.ac.server.web.SyncOutput; +import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; -import org.apache.log4j.Logger; - -import com.unboundid.ldap.sdk.LDAPException; - -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.security.AccessControlException; -import java.security.Principal; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.List; public abstract class AbstractGroupAction implements PrivilegedExceptionAction<Object> { @@ -187,19 +189,21 @@ public abstract class AbstractGroupAction implements PrivilegedExceptionAction<O } catch (TransientException e) { - String message = "Internal Transient Error: " + e.getMessage(); + String message = "Transient Error: " + e.getMessage(); this.logInfo.setSuccess(false); this.logInfo.setMessage(message); + if (e.getRetryDelay() > 0) + syncOut.setHeader("Retry-After", Integer.toString(e.getRetryDelay())); log.error(message, e); sendError(503, message); } catch (Throwable t) { + log.error("Internal Error", t); String message = "Internal Error: " + t.getMessage(); this.logInfo.setSuccess(false); - this.logInfo.setMessage(message); - log.error(message, t); sendError(500, message); + this.logInfo.setMessage(message); } return null; } @@ -233,4 +237,26 @@ public abstract class AbstractGroupAction implements PrivilegedExceptionAction<O this.logInfo.deletedMembers = deletedMembers; } + protected String getUseridForLogging(User u) + { + if (u.getIdentities().isEmpty()) + return "anonUser"; + + Iterator<Principal> i = u.getIdentities().iterator(); + String ret = null; + Principal next = null; + while (i.hasNext()) + { + next = i.next(); + if (next instanceof HttpPrincipal) + return next.getName(); + if (next instanceof X500Principal) + ret = next.getName(); + else if (ret == null) + ret = next.getName(); + } + return ret; + } + + } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberAction.java index ddc69bc68a2d1ffca77fab684fffb5cb228b807f..e0281883c2ad9198103ced8664b77ad4dd9eabd6 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberAction.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberAction.java @@ -68,17 +68,21 @@ */ package ca.nrc.cadc.ac.server.web.groups; +import java.security.Principal; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.MemberAlreadyExistsException; import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.ac.server.GroupPersistence; import ca.nrc.cadc.auth.AuthenticationUtil; -import java.security.Principal; -import java.util.ArrayList; -import java.util.List; public class AddUserMemberAction extends AbstractGroupAction { + private static final Logger log = Logger.getLogger(AddUserMemberAction.class); + private final String groupName; private final String userID; private final String userIDType; @@ -92,12 +96,14 @@ public class AddUserMemberAction extends AbstractGroupAction this.userIDType = userIDType; } - @SuppressWarnings("unchecked") + @Override public void doAction() throws Exception { Group group = groupPersistence.getGroup(this.groupName); Principal userPrincipal = AuthenticationUtil.createPrincipal(this.userID, this.userIDType); - User<Principal> toAdd = new User(userPrincipal); + User toAdd = new User(); + + toAdd.getIdentities().add(userPrincipal); if (!group.getUserMembers().add(toAdd)) { throw new MemberAlreadyExistsException(); @@ -106,7 +112,7 @@ public class AddUserMemberAction extends AbstractGroupAction groupPersistence.modifyGroup(group); List<String> addedMembers = new ArrayList<String>(); - addedMembers.add(toAdd.getUserID().getName()); + addedMembers.add(getUseridForLogging(toAdd)); logGroupInfo(group.getID(), null, addedMembers); } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/CreateGroupAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/CreateGroupAction.java index 23e93bbf8a6fa3ca75aa99dbc535f9db2320e4fa..851ca7cde22dad0787d5d12d9d6a7d9d8bba0c58 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/CreateGroupAction.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/CreateGroupAction.java @@ -69,6 +69,7 @@ package ca.nrc.cadc.ac.server.web.groups; import java.io.InputStream; +import java.security.Principal; import java.util.ArrayList; import java.util.List; @@ -107,7 +108,12 @@ public class CreateGroupAction extends AbstractGroupAction } for (User usr : group.getUserMembers()) { - addedMembers.add(usr.getUserID().getName()); + Principal p = usr.getHttpPrincipal(); + if (p == null) + { + p = usr.getX500Principal(); + } + addedMembers.add(p.getName()); } } logGroupInfo(group.getID(), null, addedMembers); diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupAction.java index 732348de3765741a28ba781c9345fb27728a0b1e..e75f01a2bcadd08cfe6f3ac73cc1c17da80f2c01 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupAction.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupAction.java @@ -72,7 +72,6 @@ import java.util.ArrayList; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.ac.server.GroupPersistence; public class DeleteGroupAction extends AbstractGroupAction { @@ -97,7 +96,7 @@ public class DeleteGroupAction extends AbstractGroupAction } for (User usr : deletedGroup.getUserMembers()) { - this.logInfo.deletedMembers.add(usr.getUserID().getName()); + this.logInfo.deletedMembers.add(usr.getHttpPrincipal().getName()); } } } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/ModifyGroupAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/ModifyGroupAction.java index 704795a141678956e4012baa23a523781aaf8db4..631e28f552e68e91e065c488635d599626b58445 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/ModifyGroupAction.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/ModifyGroupAction.java @@ -74,8 +74,8 @@ import java.util.List; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.ac.server.GroupPersistence; import ca.nrc.cadc.ac.xml.GroupReader; +import ca.nrc.cadc.profiler.Profiler; public class ModifyGroupAction extends AbstractGroupAction { @@ -93,17 +93,21 @@ public class ModifyGroupAction extends AbstractGroupAction public void doAction() throws Exception { + Profiler profiler = new Profiler(ModifyGroupAction.class); GroupReader groupReader = new GroupReader(); Group group = groupReader.read(this.inputStream); Group oldGroup = groupPersistence.getGroup(this.groupName); + profiler.checkpoint("get Group"); + groupPersistence.modifyGroup(group); + profiler.checkpoint("modify Group"); List<String> addedMembers = new ArrayList<String>(); for (User member : group.getUserMembers()) { if (!oldGroup.getUserMembers().remove(member)) { - addedMembers.add(member.getUserID().getName()); + addedMembers.add(getUseridForLogging(member)); } } for (Group gr : group.getGroupMembers()) @@ -120,7 +124,7 @@ public class ModifyGroupAction extends AbstractGroupAction List<String> deletedMembers = new ArrayList<String>(); for (User member : oldGroup.getUserMembers()) { - deletedMembers.add(member.getUserID().getName()); + deletedMembers.add(getUseridForLogging(member)); } for (Group gr : oldGroup.getGroupMembers()) { @@ -131,6 +135,7 @@ public class ModifyGroupAction extends AbstractGroupAction deletedMembers = null; } logGroupInfo(group.getID(), deletedMembers, addedMembers); + profiler.checkpoint("log GroupInfo"); syncOut.setHeader("Location", request); syncOut.setCode(303); diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberAction.java index 5e0b0ea6ce62a74f814850eebe0dc3aa7ff5d27e..b5b6960fd1728aae7946160dfb1316876dd2b27c 100755 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberAction.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberAction.java @@ -68,6 +68,10 @@ */ package ca.nrc.cadc.ac.server.web.groups; +import java.security.Principal; +import java.util.ArrayList; +import java.util.List; + import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.MemberNotFoundException; import ca.nrc.cadc.ac.User; @@ -75,19 +79,13 @@ import ca.nrc.cadc.ac.server.PluginFactory; import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.auth.AuthenticationUtil; -import javax.security.auth.x500.X500Principal; -import java.security.Principal; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - public class RemoveUserMemberAction extends AbstractGroupAction { private final String groupName; private final String userID; private final String userIDType; - RemoveUserMemberAction(String groupName, String userID, String userIDType) + public RemoveUserMemberAction(String groupName, String userID, String userIDType) { super(); this.groupName = groupName; @@ -95,30 +93,27 @@ public class RemoveUserMemberAction extends AbstractGroupAction this.userIDType = userIDType; } - @SuppressWarnings("unchecked") + @Override public void doAction() throws Exception { Group group = groupPersistence.getGroup(this.groupName); Principal userPrincipal = AuthenticationUtil.createPrincipal(this.userID, this.userIDType); - User<Principal> user = getUserPersistence().getAugmentedUser(userPrincipal); - Set<X500Principal> x500Principals = user.getIdentities(X500Principal.class); - X500Principal x500Principal = x500Principals.iterator().next(); - User<X500Principal> toRemove = new User<X500Principal>(x500Principal); - // User members is a Set of User<X500Principal> - if (!group.getUserMembers().remove(toRemove)) + User user = getUserPersistence().getAugmentedUser(userPrincipal); + + if (!group.getUserMembers().remove(user)) { throw new MemberNotFoundException(); } groupPersistence.modifyGroup(group); List<String> deletedMembers = new ArrayList<String>(); - deletedMembers.add(toRemove.getUserID().getName()); + deletedMembers.add(getUseridForLogging(user)); logGroupInfo(group.getID(), deletedMembers, null); } - protected <T extends Principal> UserPersistence<T> getUserPersistence() + protected UserPersistence getUserPersistence() { PluginFactory pluginFactory = new PluginFactory(); return pluginFactory.createUserPersistence(); diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/userrequests/AbstractUserRequestAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/userrequests/AbstractUserRequestAction.java new file mode 100644 index 0000000000000000000000000000000000000000..53530533bb6a2f1a18c93b6fd433a3249a0f79af --- /dev/null +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/userrequests/AbstractUserRequestAction.java @@ -0,0 +1,282 @@ +/* + ************************************************************************ + ******************* 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.userrequests; + +import ca.nrc.cadc.ac.ReaderException; +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserAlreadyExistsException; +import ca.nrc.cadc.ac.UserNotFoundException; +import ca.nrc.cadc.ac.UserRequest; +import ca.nrc.cadc.ac.WriterException; +import ca.nrc.cadc.ac.json.JsonUserListWriter; +import ca.nrc.cadc.ac.json.JsonUserReader; +import ca.nrc.cadc.ac.json.JsonUserRequestReader; +import ca.nrc.cadc.ac.json.JsonUserWriter; +import ca.nrc.cadc.ac.server.UserPersistence; +import ca.nrc.cadc.ac.server.web.SyncOutput; +import ca.nrc.cadc.ac.server.web.users.UserLogInfo; +import ca.nrc.cadc.ac.xml.UserListWriter; +import ca.nrc.cadc.ac.xml.UserReader; +import ca.nrc.cadc.ac.xml.UserRequestReader; +import ca.nrc.cadc.ac.xml.UserWriter; +import ca.nrc.cadc.net.TransientException; +import ca.nrc.cadc.profiler.Profiler; +import org.apache.log4j.Logger; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.security.AccessControlException; +import java.security.Principal; +import java.security.PrivilegedExceptionAction; +import java.util.Collection; + +public abstract class AbstractUserRequestAction implements PrivilegedExceptionAction<Object> +{ + private static final Logger log = Logger.getLogger(AbstractUserRequestAction.class); + public static final String DEFAULT_CONTENT_TYPE = "text/xml"; + public static final String JSON_CONTENT_TYPE = "application/json"; + private Profiler profiler = new Profiler(AbstractUserRequestAction.class); + + protected boolean isAugmentUser; + protected UserLogInfo logInfo; + protected SyncOutput syncOut; + protected UserPersistence userPersistence; + + protected String acceptedContentType = DEFAULT_CONTENT_TYPE; + + AbstractUserRequestAction() + { + this.isAugmentUser = false; + } + + public abstract void doAction() throws Exception; + + public void setAugmentUser(final boolean isAugmentUser) + { + this.isAugmentUser = isAugmentUser; + } + + public boolean isAugmentUser() + { + return this.isAugmentUser; + } + + public void setLogInfo(UserLogInfo logInfo) + { + this.logInfo = logInfo; + } + + public void setSyncOut(SyncOutput syncOut) + { + this.syncOut = syncOut; + } + + public void setUserPersistence(UserPersistence userPersistence) + { + this.userPersistence = userPersistence; + } + + public Object run() throws IOException + { + try + { + doAction(); + profiler.checkpoint("doAction"); + } + catch (AccessControlException e) + { + log.debug(e.getMessage(), e); + String message = "Permission Denied"; + this.logInfo.setMessage(message); + sendError(403, message); + } + catch (IllegalArgumentException e) + { + log.debug(e.getMessage(), e); + String message = e.getMessage(); + this.logInfo.setMessage(message); + sendError(400, message); + } + catch (ReaderException e) + { + log.debug(e.getMessage(), e); + String message = e.getMessage(); + this.logInfo.setMessage(message); + sendError(400, message); + } + catch (UserNotFoundException e) + { + log.debug(e.getMessage(), e); + String message = "User not found: " + e.getMessage(); + this.logInfo.setMessage(message); + sendError(404, message); + } + catch (UserAlreadyExistsException e) + { + log.debug(e.getMessage(), e); + String message = e.getMessage(); + this.logInfo.setMessage(message); + sendError(409, message); + } + catch (UnsupportedOperationException e) + { + log.debug(e.getMessage(), e); + this.logInfo.setMessage("Not yet implemented."); + sendError(501); + } + catch (TransientException e) + { + String message = "Transient Error: " + e.getMessage(); + this.logInfo.setSuccess(false); + this.logInfo.setMessage(message); + if (e.getRetryDelay() > 0) + syncOut.setHeader("Retry-After", Integer.toString(e.getRetryDelay())); + log.error(message, e); + sendError(503, message); + } + catch (Throwable t) + { + String message = "Internal Error: " + t.getMessage(); + this.logInfo.setSuccess(false); + this.logInfo.setMessage(message); + log.error(message, t); + sendError(500, message); + } + return null; + } + + private void sendError(int responseCode) + throws IOException + { + sendError(responseCode, null); + } + + private void sendError(int responseCode, String message) + { + syncOut.setCode(responseCode); + syncOut.setHeader("Content-Type", "text/plain"); + if (message != null) + { + try + { + syncOut.getWriter().write(message); + } + catch (IOException e) + { + log.warn("Could not write error message to output stream"); + } + } + profiler.checkpoint("sendError"); + } + + protected void logUserInfo(String userName) + { + this.logInfo.userName = userName; + } + + public void setAcceptedContentType(final String acceptedContentType) + { + this.acceptedContentType = acceptedContentType; + } + + /** + * 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 UserRequest readUserRequest(final InputStream inputStream) + throws ReaderException, IOException + { + final UserRequest userRequest; + + if (acceptedContentType.equals(DEFAULT_CONTENT_TYPE)) + { + UserRequestReader requestReader = new UserRequestReader(); + userRequest = requestReader.read(inputStream); + } + else if (acceptedContentType.equals(JSON_CONTENT_TYPE)) + { + JsonUserRequestReader requestReader = new JsonUserRequestReader(); + userRequest = requestReader.read(inputStream); + } + else + { + // Should never happen. + throw new IOException("Unknown content being asked for: " + + acceptedContentType); + } + profiler.checkpoint("readUserRequest"); + return userRequest; + } + +} diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/userrequests/CreateUserRequestAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/userrequests/CreateUserRequestAction.java new file mode 100644 index 0000000000000000000000000000000000000000..94640dd165f61a3e118d5610b16f6f4715a8062a --- /dev/null +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/userrequests/CreateUserRequestAction.java @@ -0,0 +1,96 @@ +/* + ************************************************************************ + ******************* 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.userrequests; + +import ca.nrc.cadc.ac.UserRequest; + +import java.io.InputStream; + + +public class CreateUserRequestAction extends AbstractUserRequestAction +{ + private final InputStream inputStream; + + CreateUserRequestAction(final InputStream inputStream) + { + super(); + this.inputStream = inputStream; + } + + + public void doAction() throws Exception + { + final UserRequest userRequest = readUserRequest(this.inputStream); + userPersistence.addUserRequest(userRequest); + + syncOut.setCode(201); + logUserInfo(userRequest.getUser().getHttpPrincipal().getName()); + } + +} diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/AbstractUserActionTest.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/userrequests/UserRequestActionFactory.java similarity index 55% rename from cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/AbstractUserActionTest.java rename to cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/userrequests/UserRequestActionFactory.java index 4885e98e5687b878074e5bd6efd850ba0cdb98ad..409b14b3e62f3d87102ddd68680d8dd46a9c132a 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/AbstractUserActionTest.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/userrequests/UserRequestActionFactory.java @@ -66,129 +66,103 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac.server.web.users; +package ca.nrc.cadc.ac.server.web.userrequests; -import ca.nrc.cadc.ac.UserNotFoundException; -import ca.nrc.cadc.net.TransientException; -import ca.nrc.cadc.util.Log4jInit; +import java.io.IOException; -import java.io.*; -import java.security.AccessControlException; -import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletRequest; -import org.apache.log4j.Level; import org.apache.log4j.Logger; -import static org.easymock.EasyMock.*; -import org.junit.BeforeClass; -import org.junit.Test; +import ca.nrc.cadc.ac.server.web.WebUtil; -/** - * @author jburke - */ -public class AbstractUserActionTest -{ - private final static Logger log = Logger.getLogger(AbstractUserActionTest.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); - } +public abstract class UserRequestActionFactory +{ + private static final Logger log = Logger.getLogger(UserRequestActionFactory.class); - @Test - public void testDoActionIllegalArgumentException() throws Exception - { - String message = "message"; - int responseCode = 400; - Exception e = new IllegalArgumentException("message"); - testDoAction(message, responseCode, e); - } + public abstract AbstractUserRequestAction createAction(HttpServletRequest request) + throws IllegalArgumentException, IOException; - @Test - public void testDoActionUserNotFoundException() throws Exception + public static UserRequestActionFactory httpGetFactory() { - String message = "User not found: foo"; - int responseCode = 404; - Exception e = new UserNotFoundException("foo"); - testDoAction(message, responseCode, e); + return new UserRequestActionFactory() + { + public AbstractUserRequestAction createAction(HttpServletRequest request) + throws IllegalArgumentException, IOException + { + // http get not supported + throw new UnsupportedOperationException(); + } + }; } - @Test - public void testDoActionUnsupportedOperationException() throws Exception + public static UserRequestActionFactory httpPutFactory() { - String message = "Not yet implemented."; - int responseCode = 501; - Exception e = new UnsupportedOperationException(); - testDoAction(message, responseCode, e); + return new UserRequestActionFactory() + { + public AbstractUserRequestAction createAction(HttpServletRequest request) + throws IllegalArgumentException, IOException + { + AbstractUserRequestAction action = null; + String path = request.getPathInfo(); + log.debug("path: " + path); + + String[] segments = WebUtil.getPathSegments(path); + + if (segments.length == 0) + { + action = new CreateUserRequestAction(request.getInputStream()); + } + + if (action != null) + { + log.debug("Returning action: " + action.getClass()); + return action; + } + + throw new IllegalArgumentException("Bad PUT request to " + path); + } + }; } - @Test - public void testDoActionTransientException() throws Exception + public static UserRequestActionFactory httpPostFactory() { - 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); - - UsersActionImpl action = new UsersActionImpl(); - action.setException(new TransientException("foo")); - action.doAction(); + return new UserRequestActionFactory() + { + public AbstractUserRequestAction createAction(HttpServletRequest request) + throws IllegalArgumentException, IOException + { + // http post not supported + throw new UnsupportedOperationException(); + } + }; } - private void testDoAction(String message, int responseCode, Exception e) - throws Exception + public static UserRequestActionFactory httpDeleteFactory() { - 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); - - UsersActionImpl action = new UsersActionImpl(); - action.setException(e); - action.doAction(); + return new UserRequestActionFactory() + { + public AbstractUserRequestAction createAction(HttpServletRequest request) + throws IllegalArgumentException, IOException + { + // http delete not supported + throw new UnsupportedOperationException(); + } + }; } - public class UsersActionImpl extends AbstractUserAction + public static UserRequestActionFactory httpHeadFactory() { - Exception exception; - - public UsersActionImpl() - { - super(); - } - - public void doAction() throws Exception - { - throw exception; - } - - public void setException(Exception e) + return new UserRequestActionFactory() { - this.exception = e; - } + public AbstractUserRequestAction createAction(HttpServletRequest request) + throws IllegalArgumentException, IOException + { + // http head not supported + throw new UnsupportedOperationException(); + } + }; } } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/AbstractUserAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/AbstractUserAction.java index be904211ee655f91c9e934c9ed9351acb068adb5..95453c1735db196a39265f29311ece0ebdfeabe2 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/AbstractUserAction.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/AbstractUserAction.java @@ -68,16 +68,25 @@ */ package ca.nrc.cadc.ac.server.web.users; +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.security.AccessControlException; +import java.security.PrivilegedExceptionAction; +import java.util.Collection; + +import org.apache.log4j.Logger; + import ca.nrc.cadc.ac.ReaderException; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserAlreadyExistsException; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.ac.UserRequest; +import ca.nrc.cadc.ac.WriterException; import ca.nrc.cadc.ac.json.JsonUserListWriter; import ca.nrc.cadc.ac.json.JsonUserReader; import ca.nrc.cadc.ac.json.JsonUserRequestReader; import ca.nrc.cadc.ac.json.JsonUserWriter; -import ca.nrc.cadc.ac.server.PluginFactory; import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.ac.server.web.SyncOutput; import ca.nrc.cadc.ac.xml.UserListWriter; @@ -87,47 +96,45 @@ import ca.nrc.cadc.ac.xml.UserWriter; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.profiler.Profiler; -import org.apache.log4j.Logger; - -import com.unboundid.ldap.sdk.LDAPException; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Writer; -import java.security.AccessControlException; -import java.security.Principal; -import java.security.PrivilegedExceptionAction; -import java.util.Collection; - -public abstract class AbstractUserAction<T extends Principal> implements PrivilegedExceptionAction<Object> +public abstract class AbstractUserAction implements PrivilegedExceptionAction<Object> { private static final Logger log = Logger.getLogger(AbstractUserAction.class); public static final String DEFAULT_CONTENT_TYPE = "text/xml"; public static final String JSON_CONTENT_TYPE = "application/json"; - private Profiler profiler = new Profiler(AbstractUserAction.class); - protected boolean isAugmentUser; + protected boolean isPrivilegedUser; + protected boolean isPrivilegedSubject; protected UserLogInfo logInfo; protected SyncOutput syncOut; - protected UserPersistence<T> userPersistence; + protected UserPersistence userPersistence; protected String acceptedContentType = DEFAULT_CONTENT_TYPE; AbstractUserAction() { - this.isAugmentUser = false; + this.isPrivilegedUser = false; } public abstract void doAction() throws Exception; - public void setAugmentUser(final boolean isAugmentUser) + public void setIsPrivilegedUser(boolean isPrivilegedUser) { - this.isAugmentUser = isAugmentUser; + this.isPrivilegedUser = isPrivilegedUser; } - public boolean isAugmentUser() + public boolean isPrivilegedUser() { - return this.isAugmentUser; + return this.isPrivilegedUser; + } + + public void setPrivilegedSubject(final boolean isPrivilegedSubject) + { + this.isPrivilegedSubject = isPrivilegedSubject; + } + + public boolean isPrivilegedSubject() + { + return this.isPrivilegedSubject; } public void setLogInfo(UserLogInfo logInfo) @@ -140,7 +147,7 @@ public abstract class AbstractUserAction<T extends Principal> implements Privile this.syncOut = syncOut; } - public void setUserPersistence(UserPersistence<T> userPersistence) + public void setUserPersistence(UserPersistence userPersistence) { this.userPersistence = userPersistence; } @@ -149,6 +156,7 @@ public abstract class AbstractUserAction<T extends Principal> implements Privile { try { + Profiler profiler = new Profiler(AbstractUserAction.class); doAction(); profiler.checkpoint("doAction"); } @@ -183,7 +191,7 @@ public abstract class AbstractUserAction<T extends Principal> implements Privile catch (UserAlreadyExistsException e) { log.debug(e.getMessage(), e); - String message = "User not found: " + e.getMessage(); + String message = e.getMessage(); this.logInfo.setMessage(message); sendError(409, message); } @@ -195,9 +203,11 @@ public abstract class AbstractUserAction<T extends Principal> implements Privile } catch (TransientException e) { - String message = "Internal Transient Error: " + e.getMessage(); + String message = "Transient Error: " + e.getMessage(); this.logInfo.setSuccess(false); this.logInfo.setMessage(message); + if (e.getRetryDelay() > 0) + syncOut.setHeader("Retry-After", Integer.toString(e.getRetryDelay())); log.error(message, e); sendError(503, message); } @@ -220,6 +230,7 @@ public abstract class AbstractUserAction<T extends Principal> implements Privile private void sendError(int responseCode, String message) { + Profiler profiler = new Profiler(AbstractUserAction.class); syncOut.setCode(responseCode); syncOut.setHeader("Content-Type", "text/plain"); if (message != null) @@ -254,10 +265,11 @@ public abstract class AbstractUserAction<T extends Principal> implements Privile * @return User Request instance. * @throws IOException Any reading errors. */ - protected final UserRequest<Principal> readUserRequest( - final InputStream inputStream) throws IOException + protected final UserRequest readUserRequest( + final InputStream inputStream) throws ReaderException, IOException { - final UserRequest<Principal> userRequest; + Profiler profiler = new Profiler(AbstractUserAction.class); + final UserRequest userRequest; if (acceptedContentType.equals(DEFAULT_CONTENT_TYPE)) { @@ -287,11 +299,12 @@ public abstract class AbstractUserAction<T extends Principal> implements Privile * * @throws IOException Any errors in reading the stream. */ - protected final User<Principal> readUser(final InputStream inputStream) - throws IOException + protected User readUser(final InputStream inputStream) + throws ReaderException, IOException { + Profiler profiler = new Profiler(AbstractUserAction.class); syncOut.setHeader("Content-Type", acceptedContentType); - final User<Principal> user; + final User user; if (acceptedContentType.equals(DEFAULT_CONTENT_TYPE)) { @@ -319,9 +332,10 @@ public abstract class AbstractUserAction<T extends Principal> implements Privile * @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 + protected void writeUser(final User user) + throws WriterException, IOException { + Profiler profiler = new Profiler(AbstractUserAction.class); syncOut.setHeader("Content-Type", acceptedContentType); final Writer writer = syncOut.getWriter(); @@ -343,9 +357,10 @@ public abstract class AbstractUserAction<T extends Principal> implements Privile * * @param users The Map of user IDs to names. */ - protected final <T extends Principal> void writeUsers(final Collection<User<T>> users) - throws IOException + protected void writeUsers(final Collection<User> users) + throws WriterException, IOException { + Profiler profiler = new Profiler(AbstractUserAction.class); syncOut.setHeader("Content-Type", acceptedContentType); final Writer writer = syncOut.getWriter(); diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java index cc7291e970cea438c5884dc5c6df7feecb72b3a6..e983a9caf6133044e4f6e8dfc9f9e6ff42737693 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java @@ -68,15 +68,12 @@ */ package ca.nrc.cadc.ac.server.web.users; -import java.io.InputStream; - import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.ac.UserRequest; -import ca.nrc.cadc.ac.server.UserPersistence; - -import javax.servlet.http.HttpServletResponse; -import java.security.Principal; +import javax.security.auth.x500.X500Principal; +import java.io.InputStream; +import java.security.AccessControlException; +import java.util.Set; public class CreateUserAction extends AbstractUserAction { @@ -91,11 +88,21 @@ public class CreateUserAction extends AbstractUserAction public void doAction() throws Exception { - final UserRequest<Principal> userRequest = readUserRequest(this.inputStream); - userPersistence.addPendingUser(userRequest); + if (!isPrivilegedSubject) + { + throw new AccessControlException("non-privileged user cannot create a user"); + } + + final User user = readUser(this.inputStream); + userPersistence.addUser(user); syncOut.setCode(201); - logUserInfo(userRequest.getUser().getUserID().getName()); + Set<X500Principal> x500Principals = user.getIdentities(X500Principal.class); + if (!x500Principals.isEmpty()) + { + X500Principal x500Principal = x500Principals.iterator().next(); + logUserInfo(x500Principal.getName()); + } } } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/DeleteUserAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/DeleteUserAction.java index 7bd80ebedc199d1ba090fd5d2da28698ea063543..1c220f78af2a8d2f58b863251a68c10ad7f2fbe1 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/DeleteUserAction.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/DeleteUserAction.java @@ -68,23 +68,36 @@ */ package ca.nrc.cadc.ac.server.web.users; -import ca.nrc.cadc.ac.server.UserPersistence; - +import java.security.AccessControlException; import java.security.Principal; public class DeleteUserAction extends AbstractUserAction { private final Principal userID; + private boolean markAsDeleted; - DeleteUserAction(Principal userID) + DeleteUserAction(Principal userID, boolean markAsDeleted) { super(); this.userID = userID; + this.markAsDeleted = markAsDeleted; } public void doAction() throws Exception { - userPersistence.deleteUser(userID); + if (markAsDeleted) + { + userPersistence.deactivateUser(userID); + } + else + { + // only the privileged user can do real deletes + if (!super.isPrivilegedSubject) + { + throw new AccessControlException("Forbidden"); + } + userPersistence.deleteUser(userID); + } } } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java index e50168d2408055e03d33bbee8e30e6738d37fd16..d9e9feb8979b44cfba0ac231ca313a650dd0db6a 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java @@ -67,19 +67,18 @@ ************************************************************************ */package ca.nrc.cadc.ac.server.web.users; +import java.security.AccessController; +import java.security.Principal; + +import javax.security.auth.Subject; + +import org.apache.log4j.Logger; + import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; -import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.profiler.Profiler; -import org.apache.log4j.Logger; - -import javax.security.auth.Subject; -import java.security.AccessController; -import java.security.Principal; -import java.util.Set; - public class GetUserAction extends AbstractUserAction { @@ -99,22 +98,22 @@ public class GetUserAction extends AbstractUserAction public void doAction() throws Exception { - User<Principal> user = getUser(this.userID); + User user = getUser(this.userID); profiler.checkpoint("getUser"); writeUser(user); profiler.checkpoint("writeUser"); } - protected User<Principal> getUser(Principal principal) throws Exception + protected User getUser(Principal principal) throws Exception { - User<Principal> user; + User user; /** * Special case 1 * If the calling Subject user is the notAugmentedX500User, AND it is * a GET, call the userDAO to get the User with all identities. */ - if (isAugmentUser()) + if (isPrivilegedUser()) { log.debug("getting augmented user " + principal.getName()); user = userPersistence.getAugmentedUser(principal); @@ -133,7 +132,7 @@ public class GetUserAction extends AbstractUserAction { log.debug("augmenting " + principal.getName() + " from subject"); Subject subject = Subject.getSubject(AccessController.getContext()); - user = new User<Principal>(principal); + user = new User(); user.getIdentities().addAll(subject.getPrincipals()); profiler.checkpoint("added identities"); } @@ -147,23 +146,21 @@ public class GetUserAction extends AbstractUserAction } catch (UserNotFoundException e) { - user = userPersistence.getPendingUser(principal); - profiler.checkpoint("getPendingUser"); + user = userPersistence.getUserRequest(principal); + profiler.checkpoint("getUserRequest"); } // Only return user profile info, first and last name. if (detail != null && detail.equalsIgnoreCase("display")) { user.getIdentities().clear(); - Set<PersonalDetails> details = user.getDetails(PersonalDetails.class); - if (details.isEmpty()) + user.posixDetails = null; + if (user.personalDetails == null) { String error = principal.getName() + " missing required PersonalDetails"; throw new IllegalStateException(error); } - PersonalDetails pd = details.iterator().next(); - user.details.clear(); - user.details.add(new PersonalDetails(pd.getFirstName(), pd.getLastName())); + user.personalDetails = new PersonalDetails(user.personalDetails.getFirstName(), user.personalDetails.getLastName()); profiler.checkpoint("addUserDetails"); } } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java index 08d0e40f4f95c390172eae37e00e715e6918d258..e068b98aecf4962e74ff25dee53d70925e63dab0 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java @@ -68,24 +68,21 @@ */ package ca.nrc.cadc.ac.server.web.users; +import java.io.InputStream; +import java.net.URL; +import java.security.Principal; + +import javax.security.auth.x500.X500Principal; +import javax.servlet.http.HttpServletRequest; + +import ca.nrc.cadc.ac.json.JsonUserWriter; +import org.apache.log4j.Logger; + import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.ac.server.UserPersistence; -import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.CookiePrincipal; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.IdentityType; import ca.nrc.cadc.auth.NumericPrincipal; -import org.apache.log4j.Logger; - -import javax.security.auth.x500.X500Principal; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.security.Principal; -import java.util.Iterator; -import java.util.Set; public class ModifyUserAction extends AbstractUserAction @@ -107,9 +104,9 @@ public class ModifyUserAction extends AbstractUserAction public void doAction() throws Exception { - final User<Principal> user = readUser(this.inputStream); - final User<Principal> modifiedUser = userPersistence.modifyUser(user); - logUserInfo(modifiedUser.getUserID().getName()); + final User user = readUser(this.inputStream); + final User modifiedUser = userPersistence.modifyUser(user); + logUserInfo(modifiedUser.getHttpPrincipal().getName()); final URL requestURL = new URL(request.getRequestURL().toString()); final StringBuilder sb = new StringBuilder(); @@ -130,7 +127,7 @@ public class ModifyUserAction extends AbstractUserAction String idType = null; for (Principal principal : user.getIdentities()) { - if (principal.getName().equals(modifiedUser.getUserID().getName())) + if (principal.getName().equals(modifiedUser.getHttpPrincipal().getName())) { if (principal instanceof HttpPrincipal) { diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java index a5e9a376363bb9eeb110f0aab711bc4bdd4460d8..e2a8f7ac45e09d7e52610c5cf91c8d51eb36d6c9 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java @@ -68,7 +68,15 @@ */ package ca.nrc.cadc.ac.server.web.users; -import ca.nrc.cadc.ac.User; +import java.io.IOException; +import java.security.Principal; +import java.util.UUID; + +import javax.security.auth.x500.X500Principal; +import javax.servlet.http.HttpServletRequest; + +import org.apache.log4j.Logger; + import ca.nrc.cadc.ac.server.web.WebUtil; import ca.nrc.cadc.auth.CookiePrincipal; import ca.nrc.cadc.auth.HttpPrincipal; @@ -76,13 +84,6 @@ import ca.nrc.cadc.auth.IdentityType; import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.auth.OpenIdPrincipal; import ca.nrc.cadc.net.NetUtil; -import org.apache.log4j.Logger; - -import javax.security.auth.x500.X500Principal; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.net.URL; -import java.security.Principal; public abstract class UserActionFactory @@ -112,8 +113,8 @@ public abstract class UserActionFactory else if (segments.length == 1) { String userID = NetUtil.decode(segments[0]); - User user = getUser(userID, request.getParameter("idType")); - action = new GetUserAction(user.getUserID(), request.getParameter("detail")); + Principal p = getIdentity(userID, request.getParameter("idType")); + action = new GetUserAction(p, request.getParameter("detail")); } if (action != null) @@ -201,8 +202,14 @@ public abstract class UserActionFactory if (segments.length == 1) { String userID = NetUtil.decode(segments[0]); - User user = getUser(userID, request.getParameter("idType")); - action = new DeleteUserAction(user.getUserID()); + Principal p = getIdentity(userID, request.getParameter("idType")); + String hardDelete = request.getParameter("hard"); + boolean markAsDeleted = true; + if (hardDelete != null && hardDelete.equalsIgnoreCase(Boolean.TRUE.toString())) + { + markAsDeleted = false; + } + action = new DeleteUserAction(p, markAsDeleted); } if (action != null) @@ -229,8 +236,7 @@ public abstract class UserActionFactory }; } - private static User<? extends Principal> getUser(final String userName, - final String idType) + private static Principal getIdentity(String userName, String idType) { if (idType == null || idType.isEmpty()) { @@ -238,28 +244,27 @@ public abstract class UserActionFactory } else if (idType.equalsIgnoreCase(IdentityType.USERNAME.getValue())) { - return new User<HttpPrincipal>(new HttpPrincipal(userName)); + return new HttpPrincipal(userName); } else if (idType.equalsIgnoreCase(IdentityType.X500.getValue())) { - return new User<X500Principal>(new X500Principal(userName)); + return new X500Principal(userName); } else if (idType.equalsIgnoreCase(IdentityType.CADC.getValue())) { - return new User<NumericPrincipal>(new NumericPrincipal( - Integer.parseInt(userName))); + return new NumericPrincipal(UUID.fromString(userName)); } else if (idType.equalsIgnoreCase(IdentityType.OPENID.getValue())) { - return new User<OpenIdPrincipal>(new OpenIdPrincipal(userName)); + return new OpenIdPrincipal(userName); } else if (idType.equalsIgnoreCase(IdentityType.COOKIE.getValue())) { - return new User<CookiePrincipal>(new CookiePrincipal(userName)); + return new CookiePrincipal(userName); } else { - throw new IllegalArgumentException("Unregonized userid"); + throw new IllegalArgumentException("Unrecognized userid"); } } diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/auth/AuthenticatorImpl.java b/cadcAccessControl-Server/src/ca/nrc/cadc/auth/AuthenticatorImpl.java index bc798615f89737639587538261324e664b468998..06714bb480b2696f99601c0b9791ed73178d2b5f 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/auth/AuthenticatorImpl.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/auth/AuthenticatorImpl.java @@ -94,8 +94,6 @@ public class AuthenticatorImpl implements Authenticator { private static final Logger log = Logger.getLogger(AuthenticatorImpl.class); - private Profiler profiler = new Profiler(AuthenticatorImpl.class); - public AuthenticatorImpl() { } /** @@ -104,6 +102,7 @@ public class AuthenticatorImpl implements Authenticator */ public Subject getSubject(Subject subject) { + Profiler profiler = new Profiler(AuthenticatorImpl.class); log.debug("ac augment subject: " + subject); AuthMethod am = AuthenticationUtil.getAuthMethod(subject); if (am == null || AuthMethod.ANON.equals(am)) @@ -135,9 +134,10 @@ public class AuthenticatorImpl implements Authenticator { try { + Profiler profiler = new Profiler(AuthenticatorImpl.class); PluginFactory pluginFactory = new PluginFactory(); UserPersistence userPersistence = pluginFactory.createUserPersistence(); - User<Principal> user = userPersistence.getAugmentedUser(subject.getPrincipals().iterator().next()); + User user = userPersistence.getAugmentedUser(subject.getPrincipals().iterator().next()); if (user.getIdentities() != null) { log.debug("Found " + user.getIdentities().size() + " principals after argument"); diff --git a/cadcAccessControl-Server/test/LdapConfig.test.properties b/cadcAccessControl-Server/test/LdapConfig.test.properties index 9b64724758556ec0e03cb3a716a052fb5a3622f3..fb4e93e09980d07f1c07cd90c71a952d3034f508 100644 --- a/cadcAccessControl-Server/test/LdapConfig.test.properties +++ b/cadcAccessControl-Server/test/LdapConfig.test.properties @@ -4,6 +4,7 @@ # is installed in your Java Keystore: # scp gimli2.cadc.dao.nrc.ca:~miscsw/ca.crt /tmp/ca.crt # ${JAVA_HOME}/bin/keytool -importcert -keystore ${JAVA_HOME}/jre/lib/security/cacerts -file /tmp/ca.crt +# Default keystore password is: changeit readOnly.servers = proc5-03.cadc.dao.nrc.ca readOnly.poolInitSize = 1 readOnly.poolMaxSize = 1 diff --git a/cadcAccessControl-Server/test/config/testConfig.offline.properties b/cadcAccessControl-Server/test/config/testConfig.offline.properties new file mode 100644 index 0000000000000000000000000000000000000000..55e58b1e08540e46648483b65e8a662972018fd1 --- /dev/null +++ b/cadcAccessControl-Server/test/config/testConfig.offline.properties @@ -0,0 +1,39 @@ +############################################################### +# +# Test ldap config #1 +# +# +############################################################### + +# Read-only connection pool +readOnly.servers = server1 server2 server3 +readOnly.poolInitSize = 3 +readOnly.poolMaxSize = 0 +readOnly.poolPolicy = roundRobin +readOnly.maxWait = 30000 +readOnly.createIfNeeded = false + +# Read-write connection pool +readWrite.servers = server4 server5 +readWrite.poolInitSize = 4 +readWrite.poolMaxSize = 9 +readWrite.poolPolicy = fewestConnections +readWrite.maxWait = 30000 +readWrite.createIfNeeded = false + +# Unbound-Read-only connection pool +unboundReadOnly.servers = server1 server2 server3 +unboundReadOnly.poolInitSize = 3 +unboundReadOnly.poolMaxSize = 8 +unboundReadOnly.poolPolicy = roundRobin +unboundReadOnly.maxWait = 30000 +unboundReadOnly.createIfNeeded = false + +# server configuration -- applies to all servers +dbrcHost = devLdap +port = 389 +proxyUser = uid=testproxy,ou=SpecialUsers,dc=testcanfar +usersDN = usersDN +userRequestsDN = userRequestsDN +groupsDN = groupsDN +adminGroupsDN = adminGroupsDN \ No newline at end of file diff --git a/cadcAccessControl-Server/test/config/testConfig.read-only.properties b/cadcAccessControl-Server/test/config/testConfig.read-only.properties new file mode 100644 index 0000000000000000000000000000000000000000..fdeda5e65d5eeaf08ff645d2880eda39c11257c9 --- /dev/null +++ b/cadcAccessControl-Server/test/config/testConfig.read-only.properties @@ -0,0 +1,39 @@ +############################################################### +# +# Test ldap config #1 +# +# +############################################################### + +# Read-only connection pool +readOnly.servers = server1 server2 server3 +readOnly.poolInitSize = 3 +readOnly.poolMaxSize = 8 +readOnly.poolPolicy = roundRobin +readOnly.maxWait = 30000 +readOnly.createIfNeeded = false + +# Read-write connection pool +readWrite.servers = server4 server5 +readWrite.poolInitSize = 4 +readWrite.poolMaxSize = 0 +readWrite.poolPolicy = fewestConnections +readWrite.maxWait = 30000 +readWrite.createIfNeeded = false + +# Unbound-Read-only connection pool +unboundReadOnly.servers = server1 server2 server3 +unboundReadOnly.poolInitSize = 3 +unboundReadOnly.poolMaxSize = 8 +unboundReadOnly.poolPolicy = roundRobin +unboundReadOnly.maxWait = 30000 +unboundReadOnly.createIfNeeded = false + +# server configuration -- applies to all servers +dbrcHost = devLdap +port = 389 +proxyUser = uid=testproxy,ou=SpecialUsers,dc=testcanfar +usersDN = usersDN +userRequestsDN = userRequestsDN +groupsDN = groupsDN +adminGroupsDN = adminGroupsDN \ No newline at end of file diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/AbstractLdapDAOTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/AbstractLdapDAOTest.java index 361fdd4fdff8de3c692a0eda21ab4b193272f7ef..0a7fb4153a15cada0f5ccbedeece9cf376f7d60e 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/AbstractLdapDAOTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/AbstractLdapDAOTest.java @@ -67,6 +67,22 @@ package ca.nrc.cadc.ac.server.ldap; +import ca.nrc.cadc.ac.PersonalDetails; +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserNotFoundException; +import ca.nrc.cadc.ac.UserRequest; +import ca.nrc.cadc.auth.DNPrincipal; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.auth.NumericPrincipal; +import ca.nrc.cadc.util.Log4jInit; +import org.apache.log4j.Level; +import org.junit.BeforeClass; + +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; +import java.lang.reflect.Field; +import java.util.UUID; + /** * Created by jburke on 2014-11-03. */ @@ -74,9 +90,147 @@ public class AbstractLdapDAOTest { static final String CONFIG = LdapConfig.class.getSimpleName() + ".test.properties"; + protected static final String SERVOPS_PEM = System.getProperty("user.home") + "/.pub/proxy.pem"; + static final String cadcDaoTest1_CN = "CadcDaoTest1"; + static final String cadcDaoTest2_CN = "CadcDaoTest2"; + static final String cadcDaoTest3_CN = "CadcDaoTest3"; + static final String cadcDaoTest1_X500DN = "cn=cadcdaotest1,ou=cadc,o=hia,c=ca"; + static final String cadcDaoTest2_X500DN = "cn=cadcdaotest2,ou=cadc,o=hia,c=ca"; + static final String cadcDaoTest3_X500DN = "cn=cadcdaotest3,ou=cadc,o=hia,c=ca"; + + static User cadcDaoTest1_User; + static User cadcDaoTest2_User; + static User cadcDaoTest3_User; + static User cadcDaoTest1_AugmentedUser; + static User cadcDaoTest2_AugmentedUser; + static User testMember; + + static String cadcDaoTest1_DN; + static String cadcDaoTest2_DN; + + static HttpPrincipal cadcDaoTest1_HttpPrincipal; + static HttpPrincipal cadcDaoTest2_HttpPrincipal; + static HttpPrincipal cadcDaoTest3_HttpPrincipal; + static X500Principal cadcDaoTest1_X500Principal; + static X500Principal cadcDaoTest2_X500Principal; + static X500Principal cadcDaoTest3_X500Principal; + static DNPrincipal cadcDaoTest1_DNPrincipal; + static DNPrincipal cadcDaoTest2_DNPrincipal; + + static Subject cadcDaoTest1_Subject; + static Subject cadcDaoTest2_Subject; + + static LdapConfig config; + + @BeforeClass + public static void setUpBeforeClass() + throws Exception + { + Log4jInit.setLevel("ca.nrc.cadc.ac", Level.DEBUG); + + // get the configuration of the development server from and config files... + config = getLdapConfig(); + + cadcDaoTest1_HttpPrincipal = new HttpPrincipal(cadcDaoTest1_CN); + cadcDaoTest2_HttpPrincipal = new HttpPrincipal(cadcDaoTest2_CN); + cadcDaoTest3_HttpPrincipal = new HttpPrincipal(cadcDaoTest3_CN); + + cadcDaoTest1_X500Principal = new X500Principal(cadcDaoTest1_X500DN); + cadcDaoTest2_X500Principal = new X500Principal(cadcDaoTest2_X500DN); + cadcDaoTest3_X500Principal = new X500Principal(cadcDaoTest3_X500DN); + + try + { + cadcDaoTest1_User = getUserDAO().getUser(cadcDaoTest1_HttpPrincipal); + } + catch (UserNotFoundException e) + { + User user = new User(); + user.getIdentities().add(cadcDaoTest1_HttpPrincipal); + user.getIdentities().add(cadcDaoTest1_X500Principal); + user.personalDetails = new PersonalDetails("CADC", "DAOTest1"); + user.personalDetails.email = cadcDaoTest1_CN + "@canada.ca"; + UserRequest userRequest = new UserRequest(user, "password".toCharArray()); + getUserDAO().addUserRequest(userRequest); + getUserDAO().approveUserRequest(cadcDaoTest1_HttpPrincipal); + cadcDaoTest1_User = getUserDAO().getUser(cadcDaoTest1_HttpPrincipal); + } + + try + { + cadcDaoTest2_User = getUserDAO().getUser(cadcDaoTest2_HttpPrincipal); + } + catch (UserNotFoundException e) + { + User user = new User(); + user.getIdentities().add(cadcDaoTest2_HttpPrincipal); + user.getIdentities().add(cadcDaoTest2_X500Principal); + user.personalDetails = new PersonalDetails("CADC", "DAOTest2"); + user.personalDetails.email = cadcDaoTest2_CN + "@canada.ca"; + UserRequest userRequest = new UserRequest(user, "password".toCharArray()); + getUserDAO().addUserRequest(userRequest); + getUserDAO().approveUserRequest(cadcDaoTest2_HttpPrincipal); + cadcDaoTest2_User = getUserDAO().getUser(cadcDaoTest2_HttpPrincipal); + } + + try + { + cadcDaoTest3_User = getUserDAO().getUser(cadcDaoTest3_HttpPrincipal); + } + catch (UserNotFoundException e) + { + User user = new User(); + user.getIdentities().add(cadcDaoTest3_HttpPrincipal); + user.getIdentities().add(cadcDaoTest3_X500Principal); + user.personalDetails = new PersonalDetails("CADC", "DAOTest3"); + user.personalDetails.email = cadcDaoTest3_CN + "@canada.ca"; + UserRequest userRequest = new UserRequest(user, "password".toCharArray()); + getUserDAO().addUserRequest(userRequest); + getUserDAO().approveUserRequest(cadcDaoTest3_HttpPrincipal); + cadcDaoTest3_User = getUserDAO().getUser(cadcDaoTest3_HttpPrincipal); + } + + // cadcDaoTest1 User and Subject with all Principals + cadcDaoTest1_AugmentedUser = getUserDAO().getAugmentedUser(cadcDaoTest1_HttpPrincipal); + cadcDaoTest1_Subject = new Subject(); + cadcDaoTest1_Subject.getPrincipals().addAll(cadcDaoTest1_AugmentedUser.getIdentities()); + + // cadcDaoTest2 User and Subject with all Principals + cadcDaoTest2_AugmentedUser = getUserDAO().getAugmentedUser(cadcDaoTest2_HttpPrincipal); + cadcDaoTest2_Subject = new Subject(); + cadcDaoTest2_Subject.getPrincipals().addAll(cadcDaoTest2_AugmentedUser.getIdentities()); + + // member returned by getMember contains only the fields required by the GMS + testMember = new User(); + testMember.personalDetails = new PersonalDetails("test", "member"); + testMember.getIdentities().add(cadcDaoTest1_X500Principal); + testMember.getIdentities().add(cadcDaoTest1_HttpPrincipal); + + // entryDN + cadcDaoTest1_DN = "uid=cadcdaotest1," + config.getUsersDN(); + cadcDaoTest2_DN = "uid=cadcdaotest2," + config.getUsersDN(); + + cadcDaoTest1_DNPrincipal = new DNPrincipal(cadcDaoTest1_DN); + cadcDaoTest2_DNPrincipal = new DNPrincipal(cadcDaoTest2_DN); + } + + static LdapUserDAO getUserDAO() throws Exception + { + LdapConnections connections = new LdapConnections(config); + return new LdapUserDAO(connections); + } + static protected LdapConfig getLdapConfig() { return LdapConfig.loadLdapConfig(CONFIG); } + public static void setField(Object object, Object value, String name) + throws Exception + { + Field field = object.getClass().getDeclaredField(name); + field.setAccessible(true); + field.set(object, value); + } + } diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapConfigTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapConfigTest.java index 2602442019ec617c1b11835c08b1625d7b0061ca..e51317e04dfbc7fa54f9b36da99bab26c104cc99 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapConfigTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapConfigTest.java @@ -65,19 +65,18 @@ ************************************************************************ */ - package ca.nrc.cadc.ac.server.ldap; -import java.util.Arrays; - +import ca.nrc.cadc.ac.server.ldap.LdapConfig.PoolPolicy; +import ca.nrc.cadc.ac.server.ldap.LdapConfig.SystemState; +import ca.nrc.cadc.util.Log4jInit; +import ca.nrc.cadc.util.PropertiesReader; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Test; -import ca.nrc.cadc.ac.server.ldap.LdapConfig.PoolPolicy; -import ca.nrc.cadc.util.Log4jInit; -import ca.nrc.cadc.util.PropertiesReader; +import java.util.Arrays; /** * Tests the LdapConfig class. @@ -120,6 +119,8 @@ public class LdapConfigTest Assert.assertEquals(PoolPolicy.fewestConnections, c.getReadWritePool().getPolicy()); Assert.assertEquals(30000, c.getReadWritePool().getMaxWait()); Assert.assertEquals(false, c.getReadWritePool().getCreateIfNeeded()); + + Assert.assertTrue("offline mode",c.getSystemState().equals(SystemState.ONLINE)); } catch (Throwable t) { @@ -161,6 +162,8 @@ public class LdapConfigTest Assert.assertEquals(PoolPolicy.fewestConnections, c.getReadWritePool().getPolicy()); Assert.assertEquals(30000, c.getReadWritePool().getMaxWait()); Assert.assertEquals(false, c.getReadWritePool().getCreateIfNeeded()); + + Assert.assertTrue("offline mode",c.getSystemState().equals(SystemState.ONLINE)); } catch (Throwable t) { @@ -239,4 +242,48 @@ public class LdapConfigTest } } + @Test + public void testReadOnlyMode() + { + try + { + System.setProperty(PropertiesReader.class.getName() + ".dir", "test/config"); + + LdapConfig ldapConfig = LdapConfig.loadLdapConfig("testConfig.read-only.properties"); + + Assert.assertTrue("read-only mode",ldapConfig.getSystemState().equals(SystemState.READONLY)); + } + catch (Throwable t) + { + log.error("Unexpected exception", t); + Assert.fail("Unexpected exception: " + t.getMessage()); + } + finally + { + System.clearProperty(PropertiesReader.class.getName() + ".dir"); + } + } + + @Test + public void testOfflineMode() + { + try + { + System.setProperty(PropertiesReader.class.getName() + ".dir", "test/config"); + + LdapConfig ldapConfig = LdapConfig.loadLdapConfig("testConfig.offline.properties"); + + Assert.assertTrue("offline mode",ldapConfig.getSystemState().equals(SystemState.OFFLINE)); + } + catch (Throwable t) + { + log.error("Unexpected exception", t); + Assert.fail("Unexpected exception: " + t.getMessage()); + } + finally + { + System.clearProperty(PropertiesReader.class.getName() + ".dir"); + } + } + } diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapConnectionsTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapConnectionsTest.java index 4e473f646341db804e25406643d3eacfd01c7070..fdc511fc63e5552e8a04ad732b9cc5da612d8491 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapConnectionsTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapConnectionsTest.java @@ -108,7 +108,7 @@ public class LdapConnectionsTest EasyMock.expect(persistence.getPool(LdapPersistence.POOL_READONLY)).andReturn(readPool).once(); EasyMock.expect(persistence.getPool(LdapPersistence.POOL_READWRITE)).andReturn(writePool).once(); EasyMock.expect(persistence.getPool(LdapPersistence.POOL_UNBOUNDREADONLY)).andReturn(unReadPool).once(); - EasyMock.expect(persistence.getCurrentConfig()).andReturn(null).once(); + EasyMock.expect(persistence.getCurrentConfig()).andReturn(null).anyTimes(); EasyMock.expect(readPool.getConnection()).andReturn(readConn).once(); EasyMock.expect(writePool.getConnection()).andReturn(writeConn).once(); diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapDAOTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapDAOTest.java index 1973e62163f21697b1baef7aad85d785775bab40..2e99e8a2c67379c320a63b8c46901160c2ef0c7f 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapDAOTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapDAOTest.java @@ -85,6 +85,8 @@ import org.junit.Test; import javax.security.auth.Subject; import javax.security.auth.x500.X500Principal; import java.security.PrivilegedExceptionAction; +import java.util.UUID; + import org.junit.Assert; import static org.junit.Assert.assertEquals; @@ -94,15 +96,6 @@ import static org.junit.Assert.assertTrue; public class LdapDAOTest extends AbstractLdapDAOTest { - static LdapConfig config; - - @BeforeClass - public static void setUpBeforeClass() throws Exception - { - Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); - // get the configuration of the development server from and config files... - config = getLdapConfig(); - } @Test public void testLdapBindConnection() throws Exception { @@ -157,7 +150,7 @@ public class LdapDAOTest extends AbstractLdapDAOTest }); - NumericPrincipal numPrincipal = new NumericPrincipal(1866); + NumericPrincipal numPrincipal = new NumericPrincipal(UUID.randomUUID()); subject.getPrincipals().add(numPrincipal); Subject.doAs(subject, new PrivilegedExceptionAction<Object>() diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java index b8f2034df38ee9b4cfd2929eaf068ac3c48a5d4f..62ac75804def5bf98a134b007d66b0f998f586f6 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java @@ -72,107 +72,29 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import java.security.AccessControlException; import java.security.PrivilegedExceptionAction; import java.util.Collection; import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; -import org.apache.log4j.Level; import org.apache.log4j.Logger; -import org.junit.BeforeClass; +import org.junit.Assert; import org.junit.Test; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupNotFoundException; import ca.nrc.cadc.ac.GroupProperty; -import ca.nrc.cadc.ac.Role; import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.auth.DNPrincipal; -import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.util.Log4jInit; -import org.junit.Assert; public class LdapGroupDAOTest extends AbstractLdapDAOTest { private static final Logger log = Logger.getLogger(LdapGroupDAOTest.class); - static String daoTestUid1 = "cadcdaotest1"; - static String daoTestUid2 = "cadcdaotest2"; - static String daoTestUid3 = "cadcdaotest3"; - - static String daoTestDN1 = "cn=" + daoTestUid1 + ",ou=cadc,o=hia,c=ca"; - static String daoTestDN2 = "cn=" + daoTestUid2 + ",ou=cadc,o=hia,c=ca"; - static String daoTestDN3 = "cn=" + daoTestUid3 + ",ou=cadc,o=hia,c=ca"; - static String unknownDN = "cn=foo,ou=cadc,o=hia,c=ca"; - - static String daoTestEntryDN1 = "uid=cadcdaotest1,ou=users,ou=ds,dc=testcanfar"; - static String daoTestEntryDN2 = "uid=cadcdaotest2,ou=users,ou=ds,dc=testcanfar"; - static String daoTestEntryDN3 = "uid=cadcdaotest3,ou=users,ou=ds,dc=testcanfar"; - - static DNPrincipal daoDNPrincipal1; - static DNPrincipal daoDNPrincipal2; - static DNPrincipal daoDNPrincipal3; - - static X500Principal daoTestPrincipal1; - static X500Principal daoTestPrincipal2; - static X500Principal daoTestPrincipal3; - static X500Principal unknownPrincipal; - - static User<X500Principal> daoTestUser1; - static User<X500Principal> daoTestUser2; - static User<X500Principal> daoTestUser3; - static User<X500Principal> unknownUser; - - static Subject daoTestUser1Subject; - static Subject daoTestUser2Subject; - static Subject anonSubject; - - static LdapConfig config; - - @BeforeClass - public static void setUpBeforeClass() - throws Exception - { - Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); - - // get the configuration of the development server from and config files... - config = getLdapConfig(); - - daoTestPrincipal1 = new X500Principal(daoTestDN1); - daoTestPrincipal2 = new X500Principal(daoTestDN2); - daoTestPrincipal3 = new X500Principal(daoTestDN3); - unknownPrincipal = new X500Principal(unknownDN); - - daoDNPrincipal1 = new DNPrincipal(daoTestEntryDN1); - daoDNPrincipal2 = new DNPrincipal(daoTestEntryDN2); - - daoTestUser1 = new User<X500Principal>(daoTestPrincipal1); - daoTestUser1.getIdentities().add(daoDNPrincipal1); - daoTestUser2 = new User<X500Principal>(daoTestPrincipal2); - daoTestUser2.getIdentities().add(daoDNPrincipal2); - daoTestUser3 = new User<X500Principal>(daoTestPrincipal3); - daoTestUser3.getIdentities().add(daoDNPrincipal3); - unknownUser = new User<X500Principal>(unknownPrincipal); - - daoTestUser1Subject = new Subject(); - daoTestUser1Subject.getPrincipals().add(daoTestUser1.getUserID()); - daoTestUser1Subject.getPrincipals().add(daoDNPrincipal1); - - daoTestUser2Subject = new Subject(); - daoTestUser2Subject.getPrincipals().add(daoTestUser2.getUserID()); - daoTestUser2Subject.getPrincipals().add(daoDNPrincipal2); - - anonSubject = new Subject(); - anonSubject.getPrincipals().add(unknownUser.getUserID()); - } - - LdapGroupDAO<X500Principal> getGroupDAO() throws Exception + LdapGroupDAO getGroupDAO() throws Exception { LdapConnections connections = new LdapConnections(config); - return new LdapGroupDAO<X500Principal>(connections, - new LdapUserDAO<X500Principal>(connections)); + return new LdapGroupDAO(connections, + new LdapUserDAO(connections)); } String getGroupID() @@ -184,19 +106,21 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest public void testOneGroup() throws Exception { // do everything as owner - Subject.doAs(daoTestUser1Subject, new PrivilegedExceptionAction<Object>() + Subject.doAs(cadcDaoTest1_Subject, new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { try { - Group expectGroup = new Group(getGroupID(), daoTestUser1); + Group expectGroup = new Group(getGroupID()); + setField(expectGroup, cadcDaoTest1_AugmentedUser, "owner"); getGroupDAO().addGroup(expectGroup); Group actualGroup = getGroupDAO().getGroup(expectGroup.getID(), true); log.info("addGroup: " + expectGroup.getID()); assertGroupsEqual(expectGroup, actualGroup); - Group otherGroup = new Group(getGroupID(), daoTestUser1); + Group otherGroup = new Group(getGroupID()); + setField(otherGroup, cadcDaoTest1_AugmentedUser, "owner"); getGroupDAO().addGroup(otherGroup); otherGroup = getGroupDAO().getGroup(otherGroup.getID(), true); log.info("addGroup: " + otherGroup.getID()); @@ -212,7 +136,7 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest assertGroupsEqual(expectGroup, actualGroup); // userMembers - expectGroup.getUserMembers().add(daoTestUser2); + expectGroup.getUserMembers().add(cadcDaoTest2_User); actualGroup = getGroupDAO().modifyGroup(expectGroup); assertGroupsEqual(expectGroup, actualGroup); @@ -220,15 +144,15 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest // Principals. The duplicate should be ignored // the the returned result should contain only // one entry (the dn one) - User<HttpPrincipal> duplicateIdentity = - new User<HttpPrincipal>(new HttpPrincipal(daoTestUid2)); - expectGroup.getUserMembers().add(daoTestUser2); + User duplicateIdentity = new User(); + duplicateIdentity.getIdentities().add(cadcDaoTest2_User.getHttpPrincipal()); + expectGroup.getUserMembers().add(cadcDaoTest2_User); expectGroup.getUserMembers().add(duplicateIdentity); actualGroup = getGroupDAO().modifyGroup(expectGroup); - expectGroup.getUserMembers().remove(duplicateIdentity); + //expectGroup.getUserMembers().remove(duplicateIdentity); assertGroupsEqual(expectGroup, actualGroup); - expectGroup.getUserMembers().remove(daoTestUser2); + expectGroup.getUserMembers().remove(cadcDaoTest2_User); actualGroup = getGroupDAO().modifyGroup(expectGroup); assertGroupsEqual(expectGroup, actualGroup); @@ -242,20 +166,21 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest assertGroupsEqual(expectGroup, actualGroup); expectGroup.description = "Happy testing"; - expectGroup.getUserMembers().add(daoTestUser2); + expectGroup.getUserMembers().add(cadcDaoTest2_User); expectGroup.getGroupMembers().add(otherGroup); // userAdmins - expectGroup.getUserAdmins().add(daoTestUser3); + expectGroup.getUserAdmins().add(cadcDaoTest3_User); actualGroup = getGroupDAO().modifyGroup(expectGroup); assertGroupsEqual(expectGroup, actualGroup); - expectGroup.getUserAdmins().remove(daoTestUser3); + expectGroup.getUserAdmins().remove(cadcDaoTest3_User); actualGroup = getGroupDAO().modifyGroup(expectGroup); assertGroupsEqual(expectGroup, actualGroup); // groupAdmins - Group adminGroup = new Group(getGroupID(), daoTestUser1); + Group adminGroup = new Group(getGroupID()); + setField(adminGroup, cadcDaoTest1_AugmentedUser, "owner"); getGroupDAO().addGroup(adminGroup); adminGroup = getGroupDAO().getGroup(adminGroup.getID(), true); expectGroup.getGroupAdmins().add(adminGroup); @@ -270,10 +195,10 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest // Principals. The duplicate should be ignored // the the returned result should contain only // one entry (the dn one) - expectGroup.getUserAdmins().add(daoTestUser2); + expectGroup.getUserAdmins().add(cadcDaoTest2_User); expectGroup.getUserAdmins().add(duplicateIdentity); actualGroup = getGroupDAO().modifyGroup(expectGroup); - expectGroup.getUserAdmins().remove(duplicateIdentity); + //expectGroup.getUserAdmins().remove(duplicateIdentity); assertGroupsEqual(expectGroup, actualGroup); // delete the group @@ -287,7 +212,8 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest log.info("deleted group: " + expectGroup.getID()); // reactivate the group - Group reactGroup = new Group(expectGroup.getID(), expectGroup.getOwner()); + Group reactGroup = new Group(expectGroup.getID()); + setField(reactGroup, cadcDaoTest1_AugmentedUser, "owner"); getGroupDAO().addGroup(reactGroup); log.info("create (reactivate) group: " + expectGroup.getID()); actualGroup = getGroupDAO().getGroup(expectGroup.getID(), true); @@ -299,7 +225,8 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest // create another group and make expected group // member of that group. Delete expected group after - Group expectGroup2 = new Group(getGroupID(), daoTestUser1); + Group expectGroup2 = new Group(getGroupID()); + setField(expectGroup2, cadcDaoTest1_AugmentedUser, "owner"); expectGroup2.getGroupAdmins().add(actualGroup); expectGroup2.getGroupMembers().add(actualGroup); getGroupDAO().addGroup(expectGroup2); @@ -309,7 +236,7 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest // delete the group getGroupDAO().deleteGroup(actualGroup.getID()); - + // should not be member of admin of expectGroup2 expectGroup2.getGroupAdmins().remove(actualGroup); expectGroup2.getGroupMembers().remove(actualGroup); @@ -328,25 +255,25 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest }); } - @Test +// @Test public void testGetGroupNames() throws Exception { final String groupID = getGroupID(); final String testGroup1ID = groupID + ".1"; final String testGroup2ID = groupID + ".2"; - Subject.doAs(daoTestUser1Subject, new PrivilegedExceptionAction<Object>() + Subject.doAs(cadcDaoTest1_Subject, new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { try { - Group testGroup1 = new Group(testGroup1ID, daoTestUser1); + Group testGroup1 = new Group(testGroup1ID); getGroupDAO().addGroup(testGroup1); testGroup1 = getGroupDAO().getGroup(testGroup1.getID(), true); log.debug("add group: " + testGroup1ID); - Group testGroup2 = new Group(testGroup2ID, daoTestUser1); + Group testGroup2 = new Group(testGroup2ID); getGroupDAO().addGroup(testGroup2); testGroup2 = getGroupDAO().getGroup(testGroup2.getID(), true); log.debug("add group: " + testGroup2ID); @@ -360,7 +287,7 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest } }); - Subject.doAs(daoTestUser1Subject, new PrivilegedExceptionAction<Object>() + Subject.doAs(cadcDaoTest1_Subject, new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { @@ -403,7 +330,7 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest } }); - Subject.doAs(daoTestUser1Subject, new PrivilegedExceptionAction<Object>() + Subject.doAs(cadcDaoTest1_Subject, new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { @@ -421,12 +348,12 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest }); } - @Test +// @Test public void testGetGroupExceptions() throws Exception { final String groupID = getGroupID(); - Subject.doAs(daoTestUser1Subject, new PrivilegedExceptionAction<Object>() + Subject.doAs(cadcDaoTest1_Subject, new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { @@ -437,7 +364,7 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest "GroupNotFoundException"); } catch (GroupNotFoundException ignore) {} - + try { getGroupDAO().getGroup(groupID, true); @@ -446,26 +373,25 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest } catch (GroupNotFoundException ignore) {} - getGroupDAO().addGroup(new Group(groupID, daoTestUser1)); + getGroupDAO().addGroup(new Group(groupID)); return null; } }); } - @Test +// @Test public void testModifyGroupExceptions() throws Exception { final String groupID = getGroupID(); - Subject.doAs(daoTestUser1Subject, new PrivilegedExceptionAction<Object>() + Subject.doAs(cadcDaoTest1_Subject, new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { - //getGroupDAO().addGroup(new Group(groupID, daoTestUser1)); + //getGroupDAO().addGroup(new Group(groupID, cadcDaoTest1_User)); try { - getGroupDAO().modifyGroup(new Group("fooBOGUSASFgomsi", - daoTestUser1)); + getGroupDAO().modifyGroup(new Group("fooBOGUSASFgomsi")); fail("modifyGroup with unknown user should throw " + "GroupNotFoundException"); } @@ -476,12 +402,12 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest }); } - @Test +// @Test public void testDeleteGroupExceptions() throws Exception { final String groupID = getGroupID(); - Subject.doAs(daoTestUser1Subject, new PrivilegedExceptionAction<Object>() + Subject.doAs(cadcDaoTest1_Subject, new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { @@ -500,6 +426,7 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest assertEquals(gr1, gr2); assertEquals(gr1.getID(), gr2.getID()); assertEquals(gr1.description, gr2.description); + assertEquals(gr1.getOwner(), gr2.getOwner()); assertEquals(gr1.getGroupMembers(), gr2.getGroupMembers()); @@ -509,10 +436,10 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest assertTrue(gr2.getGroupMembers().contains(gr)); } - assertEquals(gr1.getUserMembers(), gr2.getUserMembers()); - assertEquals(gr1.getUserMembers().size(), gr2.getUserMembers() - .size()); - for (User<?> user : gr1.getUserMembers()) + assertEquals(gr1.getUserMembers().size(), gr2.getUserMembers().size()); + assertTrue(gr1.getUserMembers().containsAll(gr2.getUserMembers())); + assertTrue(gr2.getUserMembers().containsAll(gr1.getUserMembers())); + for (User user : gr1.getUserMembers()) { assertTrue(gr2.getUserMembers().contains(user)); } @@ -524,10 +451,8 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest assertTrue(gr2.getGroupAdmins().contains(gr)); } - assertEquals(gr1.getUserAdmins(), gr2.getUserAdmins()); - assertEquals(gr1.getUserAdmins().size(), gr2.getUserAdmins() - .size()); - for (User<?> user : gr1.getUserAdmins()) + assertEquals(gr1.getUserAdmins().size(), gr2.getUserAdmins().size()); + for (User user : gr1.getUserAdmins()) { assertTrue(gr2.getUserAdmins().contains(user)); } diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java index 580d9b30e69fb926b336d5c42385c5a45c94f1c6..3dcb390f7932721071798cfd9a1b4b0b1f2f88b4 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java @@ -74,130 +74,72 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.File; import java.security.AccessControlException; import java.security.Principal; +import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Collection; -import java.util.Random; import javax.security.auth.Subject; import javax.security.auth.x500.X500Principal; -import org.apache.log4j.Level; import org.apache.log4j.Logger; -import org.junit.BeforeClass; import org.junit.Test; import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.ac.UserDetails; +import ca.nrc.cadc.ac.UserAlreadyExistsException; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.ac.UserRequest; import ca.nrc.cadc.auth.DNPrincipal; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; -import ca.nrc.cadc.util.Log4jInit; - -import com.unboundid.ldap.sdk.DN; +import ca.nrc.cadc.auth.SSLUtil; public class LdapUserDAOTest extends AbstractLdapDAOTest { private static final Logger log = Logger.getLogger(LdapUserDAOTest.class); - static final String testUserX509DN = "cn=cadcdaotest1,ou=cadc,o=hia,c=ca"; - static final String testUser1EntryDN = "uid=cadcdaotest1,ou=users,ou=ds,dc=testcanfar"; - static final String testUser2EntryDN = "uid=cadcdaotest2,ou=users,ou=ds,dc=testcanfar"; - static final String testPendingUserEntryDN = "uid=cadctestrequest,ou=users,ou=ds,dc=testcanfar"; - static int nextUserNumericID = 666; - - static String testUserDN; - static User<X500Principal> testUser; - static User<X500Principal> testMember; - static User<HttpPrincipal> testPendingUser; - static DNPrincipal testUser1DNPrincipal; - static DNPrincipal testUser2DNPrincipal; - static DNPrincipal testPendingUserDNPrincipal; - static LdapConfig config; - static Random ran = new Random(); // source of randomness for numeric ids - - - @BeforeClass - public static void setUpBeforeClass() - throws Exception + String createUsername() { - Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); - - // get the configuration of the development server from and config files... - config = getLdapConfig(); - X500Principal testUserX500Princ = new X500Principal(testUserX509DN); - testUser = new User<X500Principal>(testUserX500Princ); - - testPendingUser = - new User<HttpPrincipal>(new HttpPrincipal("CADCtestRequest")); - testPendingUser.details.add(new PersonalDetails("CADCtest", "Request")); - testPendingUser.getIdentities().add( - new HttpPrincipal("CADCtestRequest")); - testPendingUser.getIdentities().add( - new X500Principal( - "uid=CADCtestRequest,ou=userrequests,ou=ds,dc=testcanfar")); - testPendingUser.getIdentities().add(new NumericPrincipal(66666)); - - testUser.details.add(new PersonalDetails("CADC", "DAOTest1")); - testUser.getIdentities().add(new HttpPrincipal("CadcDaoTest1")); - testUser.getIdentities().add(testUserX500Princ); - testUser.getIdentities().add(new NumericPrincipal(666)); - - testUserDN = "uid=cadcdaotest1," + config.getUsersDN(); - - - // member returned by getMember contains only the fields required by - // the GMS - testMember = new User<X500Principal>(testUserX500Princ); - testMember.details.add(new PersonalDetails("CADC", "DAOTest1")); - testMember.getIdentities().add(new HttpPrincipal("CadcDaoTest1")); - - testUser1DNPrincipal = new DNPrincipal(testUser1EntryDN); - testUser2DNPrincipal = new DNPrincipal(testUser2EntryDN); - testPendingUserDNPrincipal = new DNPrincipal(testPendingUserEntryDN); + return "CadcDaoTestUser-" + System.currentTimeMillis(); } - <T extends Principal> LdapUserDAO<T> getUserDAO() throws Exception + @Test + public void testAddIllegalUsername() throws Exception { - LdapConnections connections = new LdapConnections(config); - return new LdapUserDAO(connections){ - protected int genNextNumericId() - { - return nextUserNumericID; - } - }; - } + // add user using HttpPrincipal + final String username = "$" + createUsername(); + final HttpPrincipal userID = new HttpPrincipal(username); - String createUsername() - { - return "CadcDaoTestUser-" + System.currentTimeMillis(); + final User httpExpected = new User(); + httpExpected.getIdentities().add(userID); + + PersonalDetails pd = new PersonalDetails("foo", "bar"); + pd.email = username + "@canada.ca"; + httpExpected.personalDetails = pd; + + UserRequest userRequest = new UserRequest(httpExpected, "123456".toCharArray()); + + try + { + final LdapUserDAO httpUserDAO = getUserDAO(); + httpUserDAO.addUserRequest(userRequest); + fail("Illegal username " + username + " should've thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) {} } - /** - * Test of addUser method, of class LdapUserDAO. - */ @Test public void testAddUser() throws Exception { + // add user using X500Principal String username = createUsername(); + final X500Principal userID = new X500Principal("cn=" + username + ",ou=cadc,o=hia,c=ca"); - HttpPrincipal userID = new HttpPrincipal(username); - X500Principal x500Principal = new X500Principal("cn=" + username + ",ou=cadc,o=hia,c=ca"); - NumericPrincipal numericPrincipal = new NumericPrincipal(ran.nextInt(Integer.MAX_VALUE)); - - final User<Principal> expected = new User<Principal>(userID); - expected.getIdentities().add(userID); - expected.getIdentities().add(x500Principal); - expected.getIdentities().add(numericPrincipal); - - expected.details.add(new PersonalDetails("foo", "bar")); - - final UserRequest<Principal> userRequest = - new UserRequest<Principal>(expected, "123456".toCharArray()); + final User testUser = new User(); + testUser.getIdentities().add(userID); DNPrincipal dnPrincipal = new DNPrincipal("uid=" + username + "," + config.getUsersDN()); Subject subject = new Subject(); @@ -210,12 +152,11 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - final LdapUserDAO<Principal> userDAO = getUserDAO(); - userDAO.addUser(userRequest); + final LdapUserDAO userDAO = getUserDAO(); + userDAO.addUser(testUser); - final User<Principal> actual = - userDAO.getUser(expected.getUserID()); - check(expected, actual); + final User actual = userDAO.getUser(userID); + check(testUser, actual); return null; } @@ -225,32 +166,31 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } } }); + + // TODO should test passing in both Http and X500 Principals } /** - * Test of addPendingUser method, of class LdapUserDAO. + * Test of addUserRequest method, of class LdapUserDAO. */ @Test - public void testAddPendingUser() throws Exception + public void testAddUserRequest() throws Exception { - String username = createUsername(); - - HttpPrincipal userID = new HttpPrincipal(username); - X500Principal x500Principal = new X500Principal("cn=" + username + ",ou=cadc,o=hia,c=ca"); - NumericPrincipal numericPrincipal = new NumericPrincipal(ran.nextInt(Integer.MAX_VALUE)); + // add user using HttpPrincipal + final String username = createUsername(); + final HttpPrincipal userID = new HttpPrincipal(username); - final User<Principal> expected = new User<Principal>(userID); - expected.getIdentities().add(userID); - expected.getIdentities().add(x500Principal); - expected.getIdentities().add(numericPrincipal); + final User expectedUser = new User(); + expectedUser.getIdentities().add(userID); - expected.details.add(new PersonalDetails("foo", "bar")); + expectedUser.personalDetails = new PersonalDetails("foo", "bar"); + expectedUser.personalDetails.email = username + "@canada.ca"; - final UserRequest<Principal> userRequest = - new UserRequest<Principal>(expected, "123456".toCharArray()); + UserRequest userRequest = new UserRequest(expectedUser, "123456".toCharArray()); - final LdapUserDAO<Principal> userDAO = getUserDAO(); - userDAO.addPendingUser(userRequest); + // Adding a new user is done anonymously + final LdapUserDAO userDAO = getUserDAO(); + userDAO.addUserRequest(userRequest); DNPrincipal dnPrincipal = new DNPrincipal("uid=" + username + "," + config.getUserRequestsDN()); Subject subject = new Subject(); @@ -264,9 +204,8 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - final User<Principal> actual = - userDAO.getPendingUser(expected.getUserID()); - check(expected, actual); + final User actualUser = userDAO.getUserRequest(userID); + check(expectedUser, actualUser); return null; } @@ -276,19 +215,58 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } } }); - } - // TODO testAddUser for an existing user + // try and add another user with the same username + final User dupUsername = new User(); + dupUsername.getIdentities().add(userID); + + dupUsername.personalDetails = new PersonalDetails("foo", "bar"); + dupUsername.personalDetails.email = username + "@foo.com"; + + UserRequest dupUsernameRequest = new UserRequest(dupUsername, "123456".toCharArray()); + + try + { + userDAO.addUserRequest(dupUsernameRequest); + fail("adding a duplicate user should throw a UserAlreadyExistsException"); + } + catch (UserAlreadyExistsException expected) + { + log.debug("expected exception: " + expected.getMessage()); + } + + // try and add another user with the same email address + final String username2 = createUsername(); + final HttpPrincipal userID2 = new HttpPrincipal(username); + + final User dupEmail = new User(); + dupEmail.getIdentities().add(userID2); + + dupEmail.personalDetails = new PersonalDetails("foo", "bar"); + dupEmail.personalDetails.email = username + "@canada.ca"; + + UserRequest dupEmailRequest = new UserRequest(dupEmail, "123456".toCharArray()); + + try + { + userDAO.addUserRequest(dupEmailRequest); + fail("adding a user with an existing email address should throw a UserAlreadyExistsException"); + } + catch (UserAlreadyExistsException expected) + { + log.debug("expected exception: " + expected.getMessage()); + } + } /** * Test of getUser method, of class LdapUserDAO. */ @Test - public void testGetUser() throws Exception + public void testGetUserWithHttpPrincipal() throws Exception { Subject subject = new Subject(); - subject.getPrincipals().add(testUser.getUserID()); - subject.getPrincipals().add(testUser1DNPrincipal); + subject.getPrincipals().add(cadcDaoTest1_HttpPrincipal); + subject.getPrincipals().add(cadcDaoTest1_DNPrincipal); // do everything as owner Subject.doAs(subject, new PrivilegedExceptionAction<Object>() @@ -298,10 +276,38 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - final LdapUserDAO<X500Principal> userDAO = getUserDAO(); - final User<X500Principal> actual = - userDAO.getUser(testUser.getUserID()); - check(testUser, actual); + final LdapUserDAO userDAO = getUserDAO(); + final User actual = userDAO.getUser(cadcDaoTest1_HttpPrincipal); + assertEquals(cadcDaoTest1_User.getHttpPrincipal(), actual.getHttpPrincipal()); + + return null; + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + } + }); + } + + @Test + public void testGetUserWithX500Principal() throws Exception + { + Subject subject = new Subject(); + subject.getPrincipals().add(cadcDaoTest1_X500Principal); + subject.getPrincipals().add(cadcDaoTest1_DNPrincipal); + + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() + throws Exception + { + try + { + final LdapUserDAO userDAO = getUserDAO(); + final User actual = userDAO.getUser(cadcDaoTest1_X500Principal); + assertEquals(cadcDaoTest1_User.getHttpPrincipal(), actual.getHttpPrincipal()); return null; } @@ -313,12 +319,94 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest }); } + /** + * Test of getAugmentedUser method, of class LdapUserDAO. + */ + @Test + public void getGetAugmentedUser() throws Exception + { + Subject subject = new Subject(); + subject.getPrincipals().add(cadcDaoTest1_HttpPrincipal); + subject.getPrincipals().add(cadcDaoTest1_DNPrincipal); + + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() + throws Exception + { + try + { + final LdapUserDAO userDAO = getUserDAO(); + final User actual = userDAO.getUser(cadcDaoTest1_HttpPrincipal); + assertEquals(cadcDaoTest1_User.getHttpPrincipal(), actual.getHttpPrincipal()); + + return null; + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + } + }); + } + + /** + * Test of getUserByEmailAddress method, of class LdapUserDAO. + */ + @Test + public void testGetUserByEmailAddress() throws Exception + { + // create a user with the email attribute + final String username = createUsername(); + final String emailAddress = username +"@canada.ca"; + final HttpPrincipal userID = new HttpPrincipal(username); + final User testUser = new User(); + testUser.personalDetails = new PersonalDetails("foo", "bar"); + testUser.personalDetails.email = username + "@canada.ca"; + testUser.getIdentities().add(userID); + + addUser(userID, testUser); + + try + { + // case 1: only one user matches the email address + testGetOneUserByEmailAddress(emailAddress, username); + } + finally + { + deleteUser(userID); + } + + } + @Test public void testGetPendingUser() throws Exception { + final String username = "CADCtestRequest"; + final String x500DN = "cn=" + username + ",ou=cadc,o=hia,c=ca"; + final HttpPrincipal httpPrincipal = new HttpPrincipal(username); + final X500Principal x500Principal = new X500Principal(x500DN); + + final User pendingUser = new User(); + pendingUser.personalDetails = new PersonalDetails("CADCtest", "Request"); + pendingUser.personalDetails.email = username + "@canada.ca"; + pendingUser.getIdentities().add(httpPrincipal); + pendingUser.getIdentities().add(x500Principal); + + UserRequest userRequest = new UserRequest(pendingUser, "123456".toCharArray()); + + try + { + final LdapUserDAO httpUserDAO = getUserDAO(); + httpUserDAO.addUserRequest(userRequest); + } + catch (UserAlreadyExistsException expected) {} + final Subject subject = new Subject(); - subject.getPrincipals().add(testPendingUser.getUserID()); - subject.getPrincipals().add(testPendingUserDNPrincipal); + subject.getPrincipals().add(httpPrincipal); + subject.getPrincipals().add(x500Principal); + subject.getPrincipals().add(new DNPrincipal(username + "," + config.getUsersDN())); // do everything as owner Subject.doAs(subject, new PrivilegedExceptionAction<Object>() @@ -327,10 +415,9 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - final LdapUserDAO<HttpPrincipal> userDAO = getUserDAO(); - final User<HttpPrincipal> actual = - userDAO.getPendingUser(testPendingUser.getUserID()); - check(testPendingUser, actual); + final LdapUserDAO userDAO = getUserDAO(); + final User actual = userDAO.getUserRequest(httpPrincipal); + check(pendingUser, actual); return null; } @@ -349,19 +436,15 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { String username = createUsername(); - HttpPrincipal userID = new HttpPrincipal(username); - X500Principal x500Principal = new X500Principal("cn=" + username + ",ou=cadc,o=hia,c=ca"); - NumericPrincipal numericPrincipal = new NumericPrincipal(ran.nextInt(Integer.MAX_VALUE)); + final HttpPrincipal httpPrincipal = new HttpPrincipal(username); - final User<Principal> expected = new User<Principal>(userID); - expected.getIdentities().add(userID); - expected.getIdentities().add(x500Principal); - expected.getIdentities().add(numericPrincipal); + final User expected = new User(); + expected.getIdentities().add(httpPrincipal); - expected.details.add(new PersonalDetails("foo", "bar")); + expected.personalDetails = new PersonalDetails("foo", "bar"); + expected.personalDetails.email = username + "@canada.ca"; - final UserRequest<Principal> userRequest = - new UserRequest<Principal>(expected, "123456".toCharArray()); + final UserRequest userRequest = new UserRequest(expected, "123456".toCharArray()); DNPrincipal dnPrincipal = new DNPrincipal("uid=" + username + "," + config.getUsersDN()); Subject subject = new Subject(); @@ -374,21 +457,21 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - final LdapUserDAO<Principal> userDAO = getUserDAO(); - userDAO.addPendingUser(userRequest); + final LdapUserDAO userDAO = getUserDAO(); + userDAO.addUserRequest(userRequest); - final User<Principal> actual = userDAO.approvePendingUser(expected.getUserID()); + final User actual = userDAO.approveUserRequest(expected.getHttpPrincipal()); assertNotNull(actual); - assertEquals(expected.getUserID(), actual.getUserID()); + assertEquals(expected.getHttpPrincipal(), actual.getHttpPrincipal()); - User<Principal> newUser = userDAO.getUser(userRequest.getUser().getUserID()); + User newUser = userDAO.getUser(userRequest.getUser().getHttpPrincipal()); assertNotNull(newUser); - assertEquals(expected.getUserID(), newUser.getUserID()); + assertEquals(expected.getHttpPrincipal(), newUser.getHttpPrincipal()); try { - userDAO.getPendingUser(userRequest.getUser().getUserID()); - fail("approved user " + userRequest.getUser().getUserID() + + userDAO.getUserRequest(userRequest.getUser().getHttpPrincipal()); + fail("approved user " + userRequest.getUser().getHttpPrincipal() + " found in pending user tree"); } catch (UserNotFoundException ignore) {} @@ -407,34 +490,32 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest public void testUpdateUser() throws Exception { // Create a test user - final User<HttpPrincipal> testUser2; + final User testUser; final String username = createUsername(); - final char[] password = "foo".toCharArray(); - HttpPrincipal principal = new HttpPrincipal(username); - testUser2 = new User<HttpPrincipal>(principal); - testUser2.getIdentities().add(principal); + final HttpPrincipal userID = new HttpPrincipal(username); + testUser = new User(); + testUser.getIdentities().add(userID); + + testUser.personalDetails = new PersonalDetails("firstName", "lastName"); + testUser.personalDetails.email = username + "@canada.ca"; - // update nextNumericId - nextUserNumericID = ran.nextInt(Integer.MAX_VALUE); - testUser2.getIdentities().add(new NumericPrincipal(nextUserNumericID)); - testUser2.details.add(new PersonalDetails("firstName", "lastName")); - final UserRequest<HttpPrincipal> userRequest = - new UserRequest<HttpPrincipal>(testUser2, password); + final UserRequest userRequest = new UserRequest(testUser, "password".toCharArray()); // add the user Subject subject = new Subject(); - subject.getPrincipals().add(testUser2.getUserID()); - subject.getPrincipals().add(testUser2DNPrincipal); - Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + subject.getPrincipals().add(userID); + final User newUser = (User) Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { - public Object run() + public User run() throws Exception { try { - final LdapUserDAO<HttpPrincipal> userDAO = getUserDAO(); - userDAO.addUser(userRequest); + final LdapUserDAO userDAO = getUserDAO(); + userDAO.addUserRequest(userRequest); + userDAO.approveUserRequest(userID); + return userDAO.getUser(userID); } catch (Exception e) { @@ -445,35 +526,25 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest }); // update the user - for (UserDetails details : testUser2.details) - { - if (details instanceof PersonalDetails) - { - PersonalDetails pd = (PersonalDetails) details; - pd.email = "email2"; - pd.address = "address2"; - pd.institute = "institute2"; - pd.city = "city2"; - pd.country = "country2"; - } - } + newUser.personalDetails.address = "address2"; + newUser.personalDetails.institute = "institute2"; + newUser.personalDetails.city = "city2"; + newUser.personalDetails.country = "country2"; // add a DN - testUser2.getIdentities().add(new X500Principal("cn=" + username + ",ou=cadc,o=hia,c=ca")); + newUser.getIdentities().add(new X500Principal("cn=" + username + ",ou=cadc,o=hia,c=ca")); - // update the user - subject.getPrincipals().add(testUser2.getUserID()); - subject.getPrincipals().add(testUser2DNPrincipal); - User<? extends Principal> updatedUser = - (User<? extends Principal>) Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + // update the userexpected + subject.getPrincipals().add(userID); + User updatedUser = (User) Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { try { - final LdapUserDAO<HttpPrincipal> userDAO = getUserDAO(); - return userDAO.modifyUser(testUser2); + final LdapUserDAO userDAO = getUserDAO(); + return userDAO.modifyUser(newUser); } catch (Exception e) { @@ -484,7 +555,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } }); assertNotNull(updatedUser); - check(testUser2, updatedUser); + check(newUser, updatedUser); } // TODO testUpdateUser for a user that doesn't exist @@ -495,18 +566,16 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest @Test public void deleteUser() throws Exception { - String userID = createUsername(); + String username = createUsername(); - HttpPrincipal httpPrincipal = new HttpPrincipal(userID); - X500Principal x500Principal = new X500Principal("cn=" + userID + ",ou=cadc,o=hia,c=ca"); + final HttpPrincipal userID = new HttpPrincipal(username); - final User<Principal> expected = new User<Principal>(httpPrincipal); - expected.getIdentities().add(httpPrincipal); - expected.getIdentities().add(x500Principal); - expected.details.add(new PersonalDetails("foo", "bar")); + final User testUser = new User(); + testUser.getIdentities().add(userID); + testUser.personalDetails = new PersonalDetails("foo", "bar"); + testUser.personalDetails.email = username + "@canada.ca"; - final UserRequest<Principal> userRequest = - new UserRequest<Principal>(expected, "123456".toCharArray()); + final UserRequest userRequest = new UserRequest(testUser, "password".toCharArray()); DNPrincipal dnPrincipal = new DNPrincipal("uid=" + userID + "," + config.getUsersDN()); Subject subject = new Subject(); @@ -520,10 +589,11 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - final LdapUserDAO<Principal> userDAO = getUserDAO(); - userDAO.addUser(userRequest); + final LdapUserDAO userDAO = getUserDAO(); + userDAO.addUserRequest(userRequest); + userDAO.approveUserRequest(userID); - userDAO.deleteUser(expected.getUserID()); + userDAO.deleteUser(userID, false); return null; } @@ -536,7 +606,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } /** - * Test of deletePendingUser method, of class LdapUserDAO. + * Test of deleteUserRequest method, of class LdapUserDAO. */ @Test public void deletePendingUser() throws Exception @@ -546,16 +616,16 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest HttpPrincipal httpPrincipal = new HttpPrincipal(userID); X500Principal x500Principal = new X500Principal("cn=" + userID + ",ou=cadc,o=hia,c=ca"); - final User<HttpPrincipal> expected = new User<HttpPrincipal>(httpPrincipal); + final User expected = new User(); expected.getIdentities().add(httpPrincipal); expected.getIdentities().add(x500Principal); - expected.details.add(new PersonalDetails("foo", "bar")); + expected.personalDetails = new PersonalDetails("foo", "bar"); + expected.personalDetails.email = userID + "@canada.ca"; - final UserRequest<HttpPrincipal> userRequest = - new UserRequest<HttpPrincipal>(expected, "123456".toCharArray()); + final UserRequest userRequest = new UserRequest(expected, "123456".toCharArray()); - final LdapUserDAO<HttpPrincipal> userDAO = getUserDAO(); - userDAO.addPendingUser(userRequest); + final LdapUserDAO userDAO = getUserDAO(); + userDAO.addUserRequest(userRequest); DNPrincipal dnPrincipal = new DNPrincipal("uid=" + userID + "," + config.getUserRequestsDN()); Subject subject = new Subject(); @@ -569,7 +639,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - userDAO.deletePendingUser(expected.getUserID()); + userDAO.deleteUserRequest(expected.getHttpPrincipal()); return null; } @@ -581,65 +651,13 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest }); } - /** - * Test of getMember. - */ - @Test - public void testGetX500User() throws Exception - { - Subject subject = new Subject(); - subject.getPrincipals().add(testUser.getUserID()); - subject.getPrincipals().add(testUser1DNPrincipal); - - // do everything as owner - Subject.doAs(subject, new PrivilegedExceptionAction<Object>() - { - public Object run() throws Exception - { - try - { - User<X500Principal> actual = getUserDAO().getX500User(new DN(testUserDN)); - check(testMember, actual); - return null; - } - catch (Exception e) - { - throw new Exception("Problems", e); - } - } - }); - - // should also work as a different user - subject = new Subject(); - subject.getPrincipals().add(new HttpPrincipal("CadcDaoTest2")); - - // do everything as owner - Subject.doAs(subject, new PrivilegedExceptionAction<Object>() - { - public Object run() - throws Exception - { - try - { - User<X500Principal> actual = getUserDAO().getX500User(new DN(testUserDN)); - check(testMember, actual); - return null; - } - catch (Exception e) - { - throw new Exception("Problems", e); - } - } - }); - } - @Test public void testGetUsers() throws Exception { // authenticated access Subject subject = new Subject(); - subject.getPrincipals().add(testUser.getUserID()); - subject.getPrincipals().add(testUser1DNPrincipal); + subject.getPrincipals().add(cadcDaoTest1_X500Principal); + subject.getPrincipals().add(cadcDaoTest1_DNPrincipal); Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { @@ -647,7 +665,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - final Collection<User<Principal>> users = getUserDAO().getUsers(); + final Collection<User> users = getUserDAO().getUsers(); assertNotNull("returned users is null", users); assertFalse("no users found", users.isEmpty()); log.debug("# users found: " + users.size()); @@ -667,8 +685,8 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { // authenticated access Subject subject = new Subject(); - subject.getPrincipals().add(testUser.getUserID()); - subject.getPrincipals().add(testUser1DNPrincipal); + subject.getPrincipals().add(cadcDaoTest1_X500Principal); + subject.getPrincipals().add(cadcDaoTest1_DNPrincipal); Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { @@ -676,7 +694,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - final Collection<User<Principal>> users = getUserDAO().getPendingUsers(); + final Collection<User> users = getUserDAO().getUserRequests(); assertNotNull("returned users is null", users); assertFalse("no users found", users.isEmpty()); log.debug("# users found: " + users.size()); @@ -697,19 +715,15 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest final String username = createUsername(); final String password = "123456"; - HttpPrincipal userID = new HttpPrincipal(username); - X500Principal x500Principal = new X500Principal("cn=" + username + ",ou=cadc,o=hia,c=ca"); - NumericPrincipal numericPrincipal = new NumericPrincipal(ran.nextInt(Integer.MAX_VALUE)); + HttpPrincipal httpPrincipal = new HttpPrincipal(username); - final User<Principal> expected = new User<Principal>(userID); - expected.getIdentities().add(userID); - expected.getIdentities().add(x500Principal); - expected.getIdentities().add(numericPrincipal); + final User testUser = new User(); + testUser.getIdentities().add(httpPrincipal); - expected.details.add(new PersonalDetails("foo", "bar")); + testUser.personalDetails = new PersonalDetails("foo", "bar"); + testUser.personalDetails.email = username + "@canada.ca"; - final UserRequest<Principal> userRequest = - new UserRequest<Principal>(expected, password.toCharArray()); + final UserRequest userRequest = new UserRequest(testUser, password.toCharArray()); DNPrincipal dnPrincipal = new DNPrincipal("uid=" + username + "," + config.getUsersDN()); Subject subject = new Subject(); @@ -723,8 +737,11 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest try { // add a user - final LdapUserDAO<Principal> userDAO = getUserDAO(); - userDAO.addUser(userRequest); + final LdapUserDAO userDAO = getUserDAO(); + userDAO.addUserRequest(userRequest); + + // approve the user + userDAO.approveUserRequest(testUser.getHttpPrincipal()); // login as the user boolean success = userDAO.doLogin(username, password); @@ -753,7 +770,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } // delete the user - userDAO.deleteUser(userRequest.getUser().getUserID()); + userDAO.deleteUser(testUser.getHttpPrincipal(), false); // login as deleted user try @@ -791,23 +808,21 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest // LDAPTestUtils.assertResultCodeEquals(startTLSResult, ResultCode.SUCCESS); // Create a test user with a known password - final User<HttpPrincipal> testUser2; + final User testUser; final String username = createUsername(); final char[] password = "foo".toCharArray(); final char[] newPassword = "bar".toCharArray(); final HttpPrincipal httpPrincipal = new HttpPrincipal(username); - testUser2 = new User<HttpPrincipal>(httpPrincipal); - testUser2.getIdentities().add(httpPrincipal); - testUser2.details.add(new PersonalDetails("firstName", "lastName")); - final UserRequest<HttpPrincipal> userRequest = - new UserRequest<HttpPrincipal>(testUser2, password); + testUser = new User(); + testUser.getIdentities().add(httpPrincipal); + testUser.personalDetails = new PersonalDetails("firstName", "lastName"); // add the user DNPrincipal dnPrincipal = new DNPrincipal("uid=" + username + "," + config.getUsersDN()); Subject subject = new Subject(); - subject.getPrincipals().add(testUser2.getUserID()); + subject.getPrincipals().add(testUser.getHttpPrincipal()); subject.getPrincipals().add(dnPrincipal); Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { @@ -816,8 +831,8 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - final LdapUserDAO<HttpPrincipal> userDAO = getUserDAO(); - userDAO.addUser(userRequest); + final LdapUserDAO userDAO = getUserDAO(); + userDAO.addUser(testUser); } catch (Exception e) { @@ -854,7 +869,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - final LdapUserDAO<HttpPrincipal> userDAO = getUserDAO(); + final LdapUserDAO userDAO = getUserDAO(); userDAO.setPassword(httpPrincipal, String.valueOf(password), String.valueOf(newPassword)); fail("should throw exception if subject and user are not the same"); @@ -867,7 +882,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest }); // change the password - subject.getPrincipals().add(testUser2.getUserID()); + subject.getPrincipals().add(testUser.getHttpPrincipal()); subject.getPrincipals().add(dnPrincipal); Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { @@ -876,7 +891,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { try { - final LdapUserDAO<HttpPrincipal> userDAO = getUserDAO(); + final LdapUserDAO userDAO = getUserDAO(); userDAO.setPassword(httpPrincipal, String.valueOf(password), String.valueOf(newPassword)); } @@ -909,17 +924,27 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } - private static void check(final User<? extends Principal> user1, - final User<? extends Principal> user2) + private static void check(final User expected, final User actual) { - assertEquals(user1, user2); - assertEquals(user1.details, user2.details); - assertEquals(user1.details.size(), user2.details.size()); - assertEquals("# principals not equal", user1.getIdentities().size(), user2.getIdentities().size()); - for( Principal princ1 : user1.getIdentities()) + if (expected.getID() != null) + { + assertEquals(expected, actual); + } + + for (Principal p : expected.getIdentities()) + { + log.debug("expected P: " + p.getName()); + } + for (Principal p : actual.getIdentities()) + { + log.debug("actual P: " + p.getName()); + } + expected.isConsistent(actual); + + for( Principal princ1 : expected.getIdentities()) { boolean found = false; - for( Principal princ2 : user2.getIdentities()) + for( Principal princ2 : actual.getIdentities()) { if (princ2.getClass() == princ1.getClass()) { @@ -933,31 +958,123 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest } assertTrue(princ1.getName(), found); } - for(UserDetails d1 : user1.details) + + assertEquals(expected.personalDetails, actual.personalDetails); + PersonalDetails pd1 = expected.personalDetails; + PersonalDetails pd2 = actual.personalDetails; + assertEquals(pd1, pd2); + + if (pd1 != null && pd2 != null) + { + assertEquals(pd1.getFirstName(), pd2.getFirstName()); + assertEquals(pd1.getLastName(), pd2.getLastName()); + assertEquals(pd1.address, pd2.address); + assertEquals(pd1.city, pd2.city); + assertEquals(pd1.country, pd2.country); + assertEquals(pd1.email, pd2.email); + assertEquals(pd1.institute, pd2.institute); + } + } + + private UserRequest createUserRequest(final HttpPrincipal userID, final String email) + { + final String username = userID.getName(); + final String password = "123456"; + + final User expected = new User(); + expected.getIdentities().add(userID); + + expected.personalDetails = new PersonalDetails("foo", "bar"); + expected.personalDetails.email = email; + + final UserRequest userRequest = new UserRequest(expected, password.toCharArray()); + + return userRequest; + } + + private void addUser(final HttpPrincipal userID, final User user) + throws Exception + { + final UserRequest userRequest = new UserRequest(user, "password".toCharArray()); + + DNPrincipal dnPrincipal = new DNPrincipal("uid=" + userID.getName() + "," + config.getUsersDN()); + Subject subject = new Subject(); + subject.getPrincipals().add(dnPrincipal); + + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { - assertTrue(user2.details.contains(d1)); - if (d1 instanceof PersonalDetails) + public Object run() throws Exception { - PersonalDetails pd1 = (PersonalDetails) d1; - boolean found = false; - for (UserDetails d2 : user2.details) + try { - if (d2 instanceof PersonalDetails) - { - PersonalDetails pd2 = (PersonalDetails) d2; - assertEquals(pd1, pd2); // already done in contains above but just in case - assertEquals(pd1.address, pd2.address); - assertEquals(pd1.city, pd2.city); - assertEquals(pd1.country, pd2.country); - assertEquals(pd1.email, pd2.email); - assertEquals(pd1.institute, pd2.institute); - found = true; - } - assertTrue(found); + getUserDAO().addUserRequest(userRequest); + getUserDAO().approveUserRequest(userID); + return null; + } + catch (Exception e) + { + throw new Exception("Problems", e); } } - } + }); + } + + private void deleteUser(final HttpPrincipal userID) + throws Exception + { + DNPrincipal dnPrincipal = new DNPrincipal("uid=" + userID.getName() + "," + config.getUsersDN()); + Subject subject = new Subject(); + subject.getPrincipals().add(dnPrincipal); + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + final LdapUserDAO userDAO = getUserDAO(); + userDAO.deleteUser(userID, false); + + return null; + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + } + }); + } + + protected void testGetOneUserByEmailAddress(final String emailAddress, final String username) + throws PrivilegedActionException + { + // do as servops + Subject servops = SSLUtil.createSubject(new File(SERVOPS_PEM)); + Subject.doAs(servops, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + final LdapUserDAO userDAO = getUserDAO(); + final User user = userDAO.getUserByEmailAddress(emailAddress); + assertNotNull(user); + PersonalDetails pd = user.personalDetails; + assertEquals(emailAddress, pd.email); + String actualName = user.getHttpPrincipal().getName(); + assertEquals(username, actualName); + + return null; + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + } + }); } + } diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/ModifyPasswordServletTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/ModifyPasswordServletTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ae310c14fae13ac99398bac4e6929ffadfddbdf9 --- /dev/null +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/ModifyPasswordServletTest.java @@ -0,0 +1,269 @@ +/* + ************************************************************************ + ******************* 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; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; + +import java.security.PrivilegedExceptionAction; + +import javax.security.auth.Subject; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Level; +import org.junit.Test; + +import ca.nrc.cadc.ac.server.UserPersistence; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.util.Log4jInit; +import ca.nrc.cadc.util.StringUtil; + + +public class ModifyPasswordServletTest +{ + + public ModifyPasswordServletTest() + { + Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); + } + + public void testSubjectAndPasswords(final Subject subject, final String oldPassword, + final String newPassword, int responseStatus) throws Exception + { + @SuppressWarnings("serial") + final ModifyPasswordServlet testSubject = new ModifyPasswordServlet() + { + @Override + Subject getSubject(final HttpServletRequest request) + { + return subject; + } + }; + + final HttpServletRequest mockRequest = + createMock(HttpServletRequest.class); + final HttpServletResponse mockResponse = + createMock(HttpServletResponse.class); + + expect(mockRequest.getPathInfo()).andReturn("users/CADCtest").once(); + expect(mockRequest.getMethod()).andReturn("POST").once(); + expect(mockRequest.getRemoteAddr()).andReturn("mysite.com").once(); + + if (!StringUtil.hasText(oldPassword) || !StringUtil.hasText(newPassword)) + { + expect(mockRequest.getParameter("old_password")).andReturn(oldPassword).once(); + expect(mockRequest.getParameter("new_password")).andReturn(newPassword).once(); + } + + if (responseStatus != 200) + { + mockResponse.setContentType("text/plain"); + expectLastCall().once(); + } + + mockResponse.setStatus(responseStatus); + expectLastCall().once(); + + replay(mockRequest, mockResponse); + + Subject.doAs(subject, new PrivilegedExceptionAction<Void>() + { + @Override + public Void run() throws Exception + { + testSubject.doPost(mockRequest, mockResponse); + return null; + } + }); + + verify(mockRequest, mockResponse); + } + + @Test + public void testModifyPasswordWithNullSubject() throws Exception + { + final Subject subject = null; + testSubjectAndPasswords(subject, "oldPass", "newPass", HttpServletResponse.SC_UNAUTHORIZED); + } + + @Test + public void testModifyPasswordWithEmptySubject() throws Exception + { + final Subject subject = new Subject();; + testSubjectAndPasswords(subject, "oldPass", "newPass", HttpServletResponse.SC_UNAUTHORIZED); + } + + @Test + public void testModifyPasswordWithMissingOldPassword() throws Exception + { + final Subject subject = new Subject();; + subject.getPrincipals().add(new HttpPrincipal("CADCtest")); + testSubjectAndPasswords(subject, "", "newPass", HttpServletResponse.SC_BAD_REQUEST); + } + + @Test + public void testModifyPasswordWithMissingNewPassword() throws Exception + { + final Subject subject = new Subject();; + subject.getPrincipals().add(new HttpPrincipal("CADCtest")); + testSubjectAndPasswords(subject, "oldPass", "", HttpServletResponse.SC_BAD_REQUEST); + } + + public void testModifyPassword(final boolean hasInternalServerError) throws Exception + { + final String oldPassword = "oldPass"; + final String newPassword = "newPass"; + HttpPrincipal userID = new HttpPrincipal("CADCtest"); + + final UserPersistence mockUserPersistence = + createMock(UserPersistence.class); + mockUserPersistence.setPassword(userID, oldPassword, newPassword); + if (hasInternalServerError) + { + expectLastCall().andThrow(new RuntimeException()); + } + + final Subject subject = new Subject(); + subject.getPrincipals().add(userID); + + @SuppressWarnings("serial") + final ModifyPasswordServlet testSubject = new ModifyPasswordServlet() + { + @Override + public void init(final ServletConfig config) throws ServletException + { + super.init(); + + userPersistence = mockUserPersistence; + } + + @Override + Subject getSubject(final HttpServletRequest request) + { + return subject; + } + }; + + final HttpServletRequest mockRequest = + createMock(HttpServletRequest.class); + final HttpServletResponse mockResponse = + createMock(HttpServletResponse.class); + + expect(mockRequest.getPathInfo()).andReturn("users/CADCtest").once(); + expect(mockRequest.getMethod()).andReturn("POST").once(); + expect(mockRequest.getRemoteAddr()).andReturn("mysite.com").once(); + expect(mockRequest.getParameter("old_password")).andReturn(oldPassword).once(); + expect(mockRequest.getParameter("new_password")).andReturn(newPassword).once(); + + if (hasInternalServerError) + { + mockResponse.setContentType("text/plain"); + expectLastCall().once(); + + mockResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + expectLastCall().once(); + } + + replay(mockRequest, mockResponse, mockUserPersistence); + + Subject.doAs(subject, new PrivilegedExceptionAction<Void>() + { + @Override + public Void run() throws Exception + { + testSubject.init(null); + testSubject.doPost(mockRequest, mockResponse); + return null; + } + }); + + verify(mockRequest, mockResponse, mockUserPersistence); + } + + + @Test + public void testModifyPasswordWithInternalServerError() throws Exception + { + boolean hasInternalServerError = true; + testModifyPassword(hasInternalServerError); + } + + @Test + public void testModifyPasswordHappyPath() throws Exception + { + boolean hasInternalServerError = false; + testModifyPassword(hasInternalServerError); + } +} diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/ResetPasswordServletTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/ResetPasswordServletTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0273c031e38365e0994eaa7f2b33287222457557 --- /dev/null +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/ResetPasswordServletTest.java @@ -0,0 +1,316 @@ +/* + ************************************************************************ + ******************* 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; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; + +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.List; + +import javax.security.auth.Subject; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Test; + +import ca.nrc.cadc.ac.UserAlreadyExistsException; +import ca.nrc.cadc.ac.UserNotFoundException; +import ca.nrc.cadc.ac.server.UserPersistence; +import ca.nrc.cadc.ac.server.ldap.LdapUserDAO; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.util.StringUtil; + + +public class ResetPasswordServletTest +{ + private static final String EMAIL_ADDRESS = "email@canada.ca"; + + public void testSubjectAndEmailAddress(final Subject subject, final String emailAddress, + int responseStatus) throws Exception + { + @SuppressWarnings("serial") + final ResetPasswordServlet testSubject = new ResetPasswordServlet() + { + @Override + Subject getSubject(final HttpServletRequest request) + { + return subject; + } + }; + + final HttpServletRequest mockRequest = + createMock(HttpServletRequest.class); + final HttpServletResponse mockResponse = + createMock(HttpServletResponse.class); + + expect(mockRequest.getPathInfo()).andReturn("users/CADCtest").once(); + expect(mockRequest.getMethod()).andReturn("POST").once(); + expect(mockRequest.getRemoteAddr()).andReturn("mysite.com").once(); + + if (!StringUtil.hasText(emailAddress)) + { + expect(mockRequest.getParameter("emailAddress")).andReturn(emailAddress).once(); + } + + mockResponse.setStatus(responseStatus); + expectLastCall().once(); + + replay(mockRequest, mockResponse); + + Subject.doAs(subject, new PrivilegedExceptionAction<Void>() + { + @Override + public Void run() throws Exception + { + testSubject.doGet(mockRequest, mockResponse); + return null; + } + }); + + verify(mockRequest, mockResponse); + } + + @Test + public void testGetWithNullSubject() throws Exception + { + final Subject subject = null; + testSubjectAndEmailAddress(subject, EMAIL_ADDRESS, HttpServletResponse.SC_UNAUTHORIZED); + } + + @Test + public void testGetWithEmptySubject() throws Exception + { + final Subject subject = new Subject();; + testSubjectAndEmailAddress(subject, EMAIL_ADDRESS, HttpServletResponse.SC_UNAUTHORIZED); + } + + public void testPrivilegedSubjectAndEmailAddress(final List<Subject> privSubjects, + final Subject subject, int responseStatus, final String emailAddress, + final UserPersistence mockUserPersistence) throws Exception + { + @SuppressWarnings("serial") + final ResetPasswordServlet testSubject = new ResetPasswordServlet() + { + @Override + public void init() throws ServletException + { + privilegedSubjects = privSubjects; + userPersistence = mockUserPersistence; + } + + @Override + protected boolean isPrivilegedSubject(final HttpServletRequest request) + { + if (privSubjects == null || privSubjects.isEmpty()) + { + return false; + } + else + { + return true; + } + } + + @Override + Subject getSubject(final HttpServletRequest request) + { + return subject; + } + }; + + final HttpServletRequest mockRequest = + createMock(HttpServletRequest.class); + final HttpServletResponse mockResponse = + createMock(HttpServletResponse.class); + + expect(mockRequest.getPathInfo()).andReturn("users/CADCtest").once(); + expect(mockRequest.getMethod()).andReturn("POST").once(); + expect(mockRequest.getRemoteAddr()).andReturn("mysite.com").once(); + + if (privSubjects != null && !privSubjects.isEmpty()) + { + if (mockUserPersistence == null) + { + expect(mockRequest.getParameter("emailAddress")).andReturn(emailAddress).once(); + } + else + { + expect(mockRequest.getParameter("emailAddress")).andReturn(emailAddress).once(); + } + } + + mockResponse.setStatus(responseStatus); + expectLastCall().once(); + + replay(mockRequest, mockResponse, mockUserPersistence); + + Subject.doAs(subject, new PrivilegedExceptionAction<Void>() + { + @Override + public Void run() throws Exception + { + testSubject.init(); + testSubject.doGet(mockRequest, mockResponse); + return null; + } + }); + + verify(mockRequest, mockResponse); + } + + @Test + public void testGetWithNullPrivilegedSubjects() throws Exception + { + final Subject subject = new Subject();; + subject.getPrincipals().add(new HttpPrincipal("CADCtest")); + UserPersistence mockUserPersistence = + (UserPersistence) createMock(UserPersistence.class); + testPrivilegedSubjectAndEmailAddress(null, subject, + HttpServletResponse.SC_FORBIDDEN, "", mockUserPersistence); + } + + @Test + public void testGetWithEmptyPrivilegedSubjects() throws Exception + { + final Subject subject = new Subject();; + subject.getPrincipals().add(new HttpPrincipal("CADCtest")); + UserPersistence mockUserPersistence = + (UserPersistence) createMock(UserPersistence.class); + testPrivilegedSubjectAndEmailAddress(new ArrayList<Subject>(), subject, + HttpServletResponse.SC_FORBIDDEN, "", mockUserPersistence); + } + + @Test + public void testGetWithMissingEmailAddress() throws Exception + { + final Subject subject = new Subject();; + subject.getPrincipals().add(new HttpPrincipal("CADCtest")); + List<Subject> privilegedSubjects = new ArrayList<Subject>(); + privilegedSubjects.add(new Subject()); + UserPersistence mockUserPersistence = + (UserPersistence) createMock(UserPersistence.class); + testPrivilegedSubjectAndEmailAddress(privilegedSubjects, subject, + HttpServletResponse.SC_BAD_REQUEST, "", mockUserPersistence); + } + + @SuppressWarnings("unchecked") + @Test + public void testGetWithMoreThanOneUserFound() throws Exception + { + final Subject subject = new Subject();; + subject.getPrincipals().add(new HttpPrincipal("CADCtest")); + List<Subject> privilegedSubjects = new ArrayList<Subject>(); + privilegedSubjects.add(new Subject()); + UserAlreadyExistsException uaee = + new UserAlreadyExistsException(LdapUserDAO.EMAIL_ADDRESS_CONFLICT_MESSAGE); + UserPersistence mockUserPersistence = + (UserPersistence) createMock(UserPersistence.class); + expect(mockUserPersistence.getUserByEmailAddress(EMAIL_ADDRESS)).andThrow(uaee); + testPrivilegedSubjectAndEmailAddress(privilegedSubjects, subject, + HttpServletResponse.SC_CONFLICT, EMAIL_ADDRESS, mockUserPersistence); + } + + @SuppressWarnings("unchecked") + @Test + public void testGetWithNoUserFound() throws Exception + { + final Subject subject = new Subject();; + subject.getPrincipals().add(new HttpPrincipal("CADCtest")); + List<Subject> privilegedSubjects = new ArrayList<Subject>(); + privilegedSubjects.add(new Subject()); + UserNotFoundException unfe = new UserNotFoundException("User with email address "); + UserPersistence mockUserPersistence = + (UserPersistence) createMock(UserPersistence.class); + expect(mockUserPersistence.getUserByEmailAddress(EMAIL_ADDRESS)).andThrow(unfe); + testPrivilegedSubjectAndEmailAddress(privilegedSubjects, subject, + HttpServletResponse.SC_NOT_FOUND, EMAIL_ADDRESS, mockUserPersistence); + } + + @SuppressWarnings("unchecked") + @Test + public void testGetWithInternalServerError() throws Exception + { + final Subject subject = new Subject();; + subject.getPrincipals().add(new HttpPrincipal("CADCtest")); + List<Subject> privilegedSubjects = new ArrayList<Subject>(); + privilegedSubjects.add(new Subject()); + RuntimeException rte = new RuntimeException(); + UserPersistence mockUserPersistence = + (UserPersistence) createMock(UserPersistence.class); + expect(mockUserPersistence.getUserByEmailAddress(EMAIL_ADDRESS)).andThrow(rte); + testPrivilegedSubjectAndEmailAddress(privilegedSubjects, subject, + HttpServletResponse.SC_INTERNAL_SERVER_ERROR, EMAIL_ADDRESS, mockUserPersistence); + } +} diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/UserLoginServletTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/UserLoginServletTest.java index 41fdab94cd324c45dd6bbc2310a461a2e37f80a6..b2927d903e9402064d08bb1bd8171e7703de02e2 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/UserLoginServletTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/UserLoginServletTest.java @@ -10,7 +10,8 @@ import java.security.AccessControlException; import java.util.Collection; import java.util.HashSet; -import ca.nrc.cadc.auth.AuthenticatorImpl; +import javax.security.auth.Subject; + import org.easymock.EasyMock; import org.junit.Test; @@ -18,10 +19,9 @@ import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.Role; import ca.nrc.cadc.ac.server.GroupDetailSelector; import ca.nrc.cadc.ac.server.ldap.LdapGroupPersistence; +import ca.nrc.cadc.auth.AuthenticatorImpl; import ca.nrc.cadc.auth.HttpPrincipal; -import javax.security.auth.Subject; - public class UserLoginServletTest { @Test @@ -75,7 +75,7 @@ public class UserLoginServletTest // } @Override - protected LdapGroupPersistence<HttpPrincipal> getLdapGroupPersistence() + protected LdapGroupPersistence getLdapGroupPersistence() { proxyGroup = "proxyGroup"; nonImpersonGroup = "niGroup"; @@ -85,8 +85,8 @@ public class UserLoginServletTest niGroups.add(new Group(nonImpersonGroup)); // mock returns a shell instance @SuppressWarnings("unchecked") - LdapGroupPersistence<HttpPrincipal> mockGp = - (LdapGroupPersistence<HttpPrincipal>)EasyMock + LdapGroupPersistence mockGp = + (LdapGroupPersistence)EasyMock .createMock(LdapGroupPersistence.class); mockGp.setDetailSelector(new GroupDetailSelector() { diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/UserRequestServletTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/UserRequestServletTest.java new file mode 100644 index 0000000000000000000000000000000000000000..127a6cc8dc6db8218ff4cd39f886951759610539 --- /dev/null +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/UserRequestServletTest.java @@ -0,0 +1,51 @@ +package ca.nrc.cadc.ac.server.web; + + +import org.junit.Test; + +import javax.servlet.http.HttpServletRequest; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; + + +public class UserRequestServletTest +{ + @Test + public void getAcceptedContentTypeJSON() throws Exception + { + final HttpServletRequest mockRequest = + createMock(HttpServletRequest.class); + final UserRequestServlet testSubject = new UserRequestServlet(); + + expect(mockRequest.getHeader("Accept")). + andReturn("application/json").once(); + + replay(mockRequest); + + assertEquals("Wrong content type.", "application/json", + testSubject.getAcceptedContentType(mockRequest)); + + verify(mockRequest); + } + + @Test + public void getAcceptedContentTypeDefault() throws Exception + { + final HttpServletRequest mockRequest = + createMock(HttpServletRequest.class); + final UserRequestServlet testSubject = new UserRequestServlet(); + + expect(mockRequest.getHeader("Accept")).andReturn(null).once(); + + replay(mockRequest); + + assertEquals("Wrong content type.", "text/xml", + testSubject.getAcceptedContentType(mockRequest)); + + verify(mockRequest); + } +} diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/WhoAmIServletTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/WhoAmIServletTest.java index 37b3d835bcf28c483a0dea4e9aee9a57aa65a41f..5e8a06a3de1c0ce9fa21ef4ed1e039980b189add 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/WhoAmIServletTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/WhoAmIServletTest.java @@ -68,20 +68,25 @@ package ca.nrc.cadc.ac.server.web; -import ca.nrc.cadc.ac.AC; -import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.reg.client.RegistryClient; -import org.junit.Test; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; + +import java.net.URI; +import java.net.URL; +import java.security.PrivilegedExceptionAction; import javax.security.auth.Subject; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.net.URI; -import java.net.URL; -import java.security.PrivilegedExceptionAction; +import org.junit.Test; -import static org.easymock.EasyMock.*; +import ca.nrc.cadc.ac.AC; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.reg.client.RegistryClient; public class WhoAmIServletTest @@ -127,8 +132,8 @@ public class WhoAmIServletTest mockResponse.sendRedirect("/ac/users/CADCtest?idType=HTTP"); expectLastCall().once(); - expect(mockRegistry.getServiceURL(URI.create(AC.GMS_SERVICE_URI), - "http", "/users/%s?idType=HTTP")). + expect(mockRegistry.getServiceURL(URI.create(AC.UMS_SERVICE_URI + "#users"), + "http", "/%s?idType=HTTP")). andReturn(new URL("http://mysite.com/ac/users/CADCtest?idType=HTTP")).once(); replay(mockRequest, mockResponse, mockRegistry); diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AbstractGroupActionTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AbstractGroupActionTest.java deleted file mode 100644 index 502e314d2992ee758465b10252986e13cc486220..0000000000000000000000000000000000000000 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AbstractGroupActionTest.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - ************************************************************************ - ******************* 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.groups; - -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.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 AbstractGroupActionTest -{ - private final static Logger log = Logger.getLogger(AbstractGroupActionTest.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 testDoActionMemberNotFoundException() throws Exception - { - String message = "Member not found: foo"; - int responseCode = 404; - Exception e = new MemberNotFoundException("foo"); - testDoAction(message, responseCode, e); - } - - @Test - public void testDoActionGroupNotFoundException() throws Exception - { - String message = "Group not found: foo"; - int responseCode = 404; - Exception e = new GroupNotFoundException("foo"); - 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 testDoActionMemberAlreadyExistsException() throws Exception - { - String message = "Member already exists: foo"; - int responseCode = 409; - Exception e = new MemberAlreadyExistsException("foo"); - testDoAction(message, responseCode, e); - } - - @Test - public void testDoActionGroupAlreadyExistsException() throws Exception - { - String message = "Group already exists: foo"; - int responseCode = 409; - Exception e = new GroupAlreadyExistsException("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); - - GroupsActionImpl action = new GroupsActionImpl(); - action.setException(new TransientException("foo")); - action.doAction(); - } - 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); - - GroupsActionImpl action = new GroupsActionImpl(); - action.setException(e); - action.doAction(); - } - catch (Throwable t) - { - log.error(t.getMessage(), t); - fail("unexpected error: " + t.getMessage()); - } - } - - public class GroupsActionImpl extends AbstractGroupAction - { - Exception exception; - - public GroupsActionImpl() - { - super(); - } - - public void doAction() throws Exception - { - throw exception; - } - - public void setException(Exception e) - { - this.exception = e; - } - } - -} diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddGroupMemberActionTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddGroupMemberActionTest.java index c801b283eadfcb0dae68251deec9d82be21f28c4..f278f25085163e76e0c6d5bae757263bb9369d7c 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddGroupMemberActionTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddGroupMemberActionTest.java @@ -103,8 +103,8 @@ public class AddGroupMemberActionTest { try { - Group group = new Group("group", null); - Group member = new Group("member", null); + Group group = new Group("group"); + Group member = new Group("member"); group.getGroupMembers().add(member); final GroupPersistence groupPersistence = createMock(GroupPersistence.class); @@ -134,9 +134,9 @@ public class AddGroupMemberActionTest { try { - Group group = new Group("group", null); - Group member = new Group("member", null); - Group modified = new Group("group", null); + Group group = new Group("group"); + Group member = new Group("member"); + Group modified = new Group("group"); modified.getGroupMembers().add(member); final GroupPersistence groupPersistence = diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberActionTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberActionTest.java index 3191fca5682572fb0cb46769236ef3a8f013c003..b40e0cd35e80d6156b6e59ba3e11c9e337fbfd24 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberActionTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/AddUserMemberActionTest.java @@ -110,9 +110,10 @@ public class AddUserMemberActionTest String userID = "foo"; String userIDType = IdentityType.USERNAME.getValue(); Principal userPrincipal = AuthenticationUtil.createPrincipal(userID, userIDType); - User<Principal> user = new User<Principal>(userPrincipal); + User user = new User(); + user.getIdentities().add(userPrincipal); - Group group = new Group("group", null); + Group group = new Group("group"); group.getUserMembers().add(user); final GroupPersistence groupPersistence = EasyMock.createMock(GroupPersistence.class); @@ -145,10 +146,11 @@ public class AddUserMemberActionTest String userID = "foo"; String userIDType = IdentityType.USERNAME.getValue(); Principal userPrincipal = AuthenticationUtil.createPrincipal(userID, userIDType); - User<Principal> user = new User<Principal>(userPrincipal); + User user = new User(); + user.getIdentities().add(userPrincipal); - Group group = new Group("group", null); - Group modified = new Group("group", null); + Group group = new Group("group"); + Group modified = new Group("group"); modified.getUserMembers().add(user); final GroupPersistence groupPersistence = EasyMock.createMock(GroupPersistence.class); diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupActionTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupActionTest.java index f0569eb57cd280994c119f0148f3abe5d5735674..62abd28a95cf318f7af7e43857a0d7c2d4197623 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupActionTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/DeleteGroupActionTest.java @@ -100,7 +100,7 @@ public class DeleteGroupActionTest { try { - Group group = new Group("group", null); + Group group = new Group("group"); final GroupPersistence groupPersistence = EasyMock.createMock(GroupPersistence.class); EasyMock.expect(groupPersistence.getGroup("group")).andReturn(group); diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveGroupMemberActionTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveGroupMemberActionTest.java index c30e9b3dd6b769d05d69c18083acef63eed395e6..f2bfc058c81dcd7ef3e9d4120f012326e676cd8e 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveGroupMemberActionTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveGroupMemberActionTest.java @@ -101,8 +101,8 @@ public class RemoveGroupMemberActionTest { try { - Group group = new Group("group", null); - Group member = new Group("member", null); + Group group = new Group("group"); + Group member = new Group("member"); final GroupPersistence groupPersistence = EasyMock.createMock(GroupPersistence.class); EasyMock.expect(groupPersistence.getGroup("group")).andReturn(group); @@ -131,11 +131,11 @@ public class RemoveGroupMemberActionTest { try { - Group member = new Group("member", null); - Group group = new Group("group", null); + Group member = new Group("member"); + Group group = new Group("group"); group.getGroupMembers().add(member); - Group modified = new Group("group", null); + Group modified = new Group("group"); modified.getGroupMembers().add(member); final GroupPersistence groupPersistence = EasyMock.createMock(GroupPersistence.class); diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberActionTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberActionTest.java index 05a9f11ab48c0ccf94166c4c620f9fdf5e26fc64..d12fc441d495414ac8b4fa84b6df56af7750392f 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberActionTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/groups/RemoveUserMemberActionTest.java @@ -71,9 +71,16 @@ package ca.nrc.cadc.ac.server.web.groups; import static org.easymock.EasyMock.createMock; import static org.junit.Assert.fail; +import java.net.URI; import java.security.Principal; +import java.util.UUID; -import ca.nrc.cadc.ac.server.UserPersistence; +import javax.security.auth.x500.X500Principal; + +import ca.nrc.cadc.ac.AC; +import ca.nrc.cadc.ac.InternalID; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.util.ObjectUtil; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.easymock.EasyMock; @@ -84,12 +91,11 @@ import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.MemberNotFoundException; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.server.GroupPersistence; +import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.IdentityType; import ca.nrc.cadc.util.Log4jInit; -import javax.security.auth.x500.X500Principal; - /** * * @author jburke @@ -110,27 +116,32 @@ public class RemoveUserMemberActionTest { try { + User user = new User(); + InternalID internalID = new InternalID(new URI(AC.USER_URI + "?" + UUID.randomUUID())); + ObjectUtil.setField(user, internalID, "id"); + String userID = "cn=foo,c=ca"; String userIDType = IdentityType.X500.getValue(); - Principal userPrincipal = AuthenticationUtil.createPrincipal(userID, userIDType); - User<Principal> user = new User<Principal>(userPrincipal); - user.getIdentities().add(userPrincipal); + Principal x500Principal = AuthenticationUtil.createPrincipal(userID, userIDType); + user.getIdentities().add(x500Principal); - Group group = new Group("group", null); - group.getUserMembers().add(new <X500Principal>User(new X500Principal("cn=bar,c=ca"))); + Group group = new Group("group"); + User member = new User(); + member.getIdentities().add(new X500Principal("cn=bar,c=ca")); + group.getUserMembers().add(member); final GroupPersistence mockGroupPersistence = EasyMock.createMock(GroupPersistence.class); EasyMock.expect(mockGroupPersistence.getGroup("group")).andReturn(group); - final UserPersistence<Principal> mockUserPersistence = EasyMock.createMock(UserPersistence.class); - EasyMock.expect(mockUserPersistence.getAugmentedUser(userPrincipal)).andReturn(user); + final UserPersistence mockUserPersistence = EasyMock.createMock(UserPersistence.class); + EasyMock.expect(mockUserPersistence.getAugmentedUser(x500Principal)).andReturn(user); EasyMock.replay(mockGroupPersistence, mockUserPersistence); RemoveUserMemberAction action = new RemoveUserMemberAction("group", userID, userIDType) { @Override - protected UserPersistence<Principal> getUserPersistence() + protected UserPersistence getUserPersistence() { return mockUserPersistence; } @@ -157,13 +168,17 @@ public class RemoveUserMemberActionTest { try { + User user = new User(); + InternalID internalID = new InternalID(new URI(AC.USER_URI + "?" + UUID.randomUUID())); + ObjectUtil.setField(user, internalID, "id"); + String userID = "cn=foo,c=ca"; String userIDType = IdentityType.X500.getValue(); Principal userPrincipal = AuthenticationUtil.createPrincipal(userID, userIDType); - User<Principal> user = new User<Principal>(userPrincipal); user.getIdentities().add(new X500Principal(userID)); + user.getIdentities().add(new HttpPrincipal("foo")); - Group group = new Group("group", null); + Group group = new Group("group"); group.getUserMembers().add(user); final GroupPersistence mockGroupPersistence = EasyMock.createMock(GroupPersistence.class); @@ -171,7 +186,7 @@ public class RemoveUserMemberActionTest mockGroupPersistence.modifyGroup(group); EasyMock.expectLastCall(); - final UserPersistence<Principal> mockUserPersistence = EasyMock.createMock(UserPersistence.class); + final UserPersistence mockUserPersistence = EasyMock.createMock(UserPersistence.class); EasyMock.expect(mockUserPersistence.getAugmentedUser(userPrincipal)).andReturn(user); EasyMock.replay(mockGroupPersistence, mockUserPersistence); @@ -179,7 +194,7 @@ public class RemoveUserMemberActionTest RemoveUserMemberAction action = new RemoveUserMemberAction("group", userID, userIDType) { @Override - protected UserPersistence<Principal> getUserPersistence() + protected UserPersistence getUserPersistence() { return mockUserPersistence; } @@ -189,6 +204,8 @@ public class RemoveUserMemberActionTest GroupLogInfo logInfo = createMock(GroupLogInfo.class); action.setLogInfo(logInfo); action.doAction(); + + EasyMock.verify(mockGroupPersistence, mockUserPersistence); } catch (Throwable t) { diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/userrequests/CreateUserRequestActionTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/userrequests/CreateUserRequestActionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6313aadfddc0bdbe57e607af174338316873be25 --- /dev/null +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/userrequests/CreateUserRequestActionTest.java @@ -0,0 +1,81 @@ +/* + ************************************************************************ + ******************* 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.userrequests; + +import org.junit.Test; + +public class CreateUserRequestActionTest +{ + @Test + public void testCreateUser() throws Exception + { + + } +} diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/userrequests/UserRequestActionFactoryTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/userrequests/UserRequestActionFactoryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..36bd03f9dfdac17a8a0d519e05861d4598a3aed0 --- /dev/null +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/userrequests/UserRequestActionFactoryTest.java @@ -0,0 +1,294 @@ +/** + ************************************************************************ + ******************* 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.userrequests; + +import ca.nrc.cadc.ac.server.web.users.AbstractUserAction; +import ca.nrc.cadc.ac.server.web.users.CreateUserAction; +import ca.nrc.cadc.ac.server.web.users.DeleteUserAction; +import ca.nrc.cadc.ac.server.web.users.GetUserAction; +import ca.nrc.cadc.ac.server.web.users.GetUserListAction; +import ca.nrc.cadc.ac.server.web.users.ModifyUserAction; +import ca.nrc.cadc.ac.server.web.users.UserActionFactory; +import ca.nrc.cadc.util.Log4jInit; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Test; + +import javax.servlet.http.HttpServletRequest; + + +public class UserRequestActionFactoryTest +{ + private final static Logger log = Logger.getLogger(UserRequestActionFactoryTest.class); + + public UserRequestActionFactoryTest() + { + Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); + } + + @Test + public void testCreateUserRequestAction() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.expect(request.getPathInfo()).andReturn(""); + EasyMock.expect(request.getInputStream()).andReturn(null); + EasyMock.replay(request); + AbstractUserRequestAction action = UserRequestActionFactory.httpPutFactory().createAction(request); + EasyMock.verify(request); + Assert.assertTrue("Wrong action", action instanceof CreateUserRequestAction); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testDeleteUserRequestAction() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.replay(request); + try + { + UserRequestActionFactory.httpDeleteFactory().createAction(request); + Assert.fail("Should have been a bad request"); + } + catch (UnsupportedOperationException e) + { + // expected + } + EasyMock.verify(request); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testGetUserRequestAction() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.replay(request); + try + { + UserRequestActionFactory.httpGetFactory().createAction(request); + Assert.fail("Should have been a bad request"); + } + catch (UnsupportedOperationException e) + { + // expected + } + EasyMock.verify(request); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testGetUserRequestNamesAction() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.replay(request); + try + { + UserRequestActionFactory.httpGetFactory().createAction(request); + Assert.fail("Should have been a bad request"); + } + catch (UnsupportedOperationException e) + { + // expected + } + EasyMock.verify(request); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testModifyUserRequestAction() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.replay(request); + try + { + UserRequestActionFactory.httpPostFactory().createAction(request); + Assert.fail("Should have been a bad request"); + } + catch (UnsupportedOperationException e) + { + // expected + } + EasyMock.verify(request); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testBadPostRequest() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.expect(request.getPathInfo()).andReturn(""); + EasyMock.replay(request); + try + { + UserActionFactory.httpPostFactory().createAction(request); + Assert.fail("Should have been a bad request"); + } + catch (IllegalArgumentException e) + { + // expected + } + EasyMock.verify(request); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testBadDeleteRequest() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.expect(request.getPathInfo()).andReturn(""); + EasyMock.replay(request); + try + { + UserActionFactory.httpDeleteFactory().createAction(request); + Assert.fail("Should have been a bad request"); + } + catch (IllegalArgumentException e) + { + // expected + } + EasyMock.verify(request); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + @Test + public void testBadHeadRequest() + { + try + { + HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); + EasyMock.replay(request); + try + { + UserActionFactory.httpHeadFactory().createAction(request); + Assert.fail("Should have been a bad request"); + } + catch (UnsupportedOperationException e) + { + // expected + } + EasyMock.verify(request); + } + catch (Throwable t) + { + log.error(t.getMessage(), t); + Assert.fail("unexpected error: " + t.getMessage()); + } + } + + +} diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/CreateUserActionTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/CreateUserActionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0160822c152d52a0cd5e609333819d56560776ed --- /dev/null +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/CreateUserActionTest.java @@ -0,0 +1,81 @@ +/* + ************************************************************************ + ******************* 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 org.junit.Test; + +public class CreateUserActionTest +{ + @Test + public void testCreateUser() throws Exception + { + + } +} diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserActionTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserActionTest.java index 8b94f8a8f21ff32bbcb151430b5122b60006f85f..70493c2d9b528b93a7c9158bfd36947b1c15c251 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserActionTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserActionTest.java @@ -67,6 +67,28 @@ */ package ca.nrc.cadc.ac.server.web.users; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.security.PrivilegedExceptionAction; +import java.util.Set; +import java.util.UUID; + +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.Test; + import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.PosixDetails; import ca.nrc.cadc.ac.User; @@ -77,45 +99,30 @@ import ca.nrc.cadc.ac.xml.UserWriter; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.util.Log4jInit; -import org.junit.Test; - -import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; -import javax.servlet.http.HttpServletResponse; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.Writer; -import java.security.Principal; -import java.security.PrivilegedExceptionAction; -import java.util.Set; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; - -import static org.easymock.EasyMock.*; -import static org.junit.Assert.assertEquals; public class GetUserActionTest { private static final Logger log = Logger.getLogger(GetUserActionTest.class); - + static { Log4jInit.setLevel("ca.nrc.cadc.ac.server", Level.INFO); } - + @Test public void writeUserXML() throws Exception { final SyncOutput mockSyncOut = createMock(SyncOutput.class); - final UserPersistence<HttpPrincipal> mockUserPersistence = + final UserPersistence mockUserPersistence = createMock(UserPersistence.class); final HttpPrincipal userID = new HttpPrincipal("CADCtest"); final GetUserAction testSubject = new GetUserAction(userID, null); testSubject.userPersistence = mockUserPersistence; - final User<HttpPrincipal> user = new User<HttpPrincipal>(userID); + final User user = new User(); + user.getIdentities().add(userID); final Writer writer = new StringWriter(); final PrintWriter printWriter = new PrintWriter(writer); @@ -141,7 +148,7 @@ public class GetUserActionTest public void writeUserWithDetailIdentity() throws Exception { final HttpPrincipal httpPrincipal = new HttpPrincipal("CADCtest"); - final NumericPrincipal numericPrincipal = new NumericPrincipal(789); + final NumericPrincipal numericPrincipal = new NumericPrincipal(UUID.randomUUID()); final X500Principal x500Principal = new X500Principal("cn=foo,o=bar"); Subject testUser = new Subject(); @@ -155,14 +162,14 @@ public class GetUserActionTest { final HttpServletResponse mockResponse = createMock(HttpServletResponse.class); - final UserPersistence<HttpPrincipal> mockUserPersistence = + final UserPersistence mockUserPersistence = createMock(UserPersistence.class); final GetUserAction testSubject = new GetUserAction(httpPrincipal, "identity"); testSubject.userPersistence = mockUserPersistence; - final User<HttpPrincipal> expected = new User<HttpPrincipal>(httpPrincipal); + final User expected = new User(); expected.getIdentities().add(httpPrincipal); expected.getIdentities().add(numericPrincipal); expected.getIdentities().add(x500Principal); @@ -172,12 +179,10 @@ public class GetUserActionTest userWriter.write(expected, sb); String expectedUser = sb.toString(); - final PersonalDetails personalDetails = new PersonalDetails("cadc", "test"); - personalDetails.city = "city"; - expected.details.add(personalDetails); + expected.personalDetails = new PersonalDetails("cadc", "test"); + expected.personalDetails.city = "city"; - final PosixDetails posixDetails = new PosixDetails(123L, 456L, "/dev/null"); - expected.details.add(posixDetails); + expected.posixDetails= new PosixDetails("username", 123L, 456L, "/dev/null"); final Writer writer = new StringWriter(); final PrintWriter printWriter = new PrintWriter(writer); @@ -207,32 +212,25 @@ public class GetUserActionTest public void writeUserWithDetailDisplay() throws Exception { final HttpServletResponse mockResponse = createMock(HttpServletResponse.class); - final UserPersistence<HttpPrincipal> mockUserPersistence = - createMock(UserPersistence.class); + final UserPersistence mockUserPersistence = createMock(UserPersistence.class); final HttpPrincipal userID = new HttpPrincipal("CADCtest"); final GetUserAction testSubject = new GetUserAction(userID, "display"); testSubject.userPersistence = mockUserPersistence; - final User<HttpPrincipal> expected = new User<HttpPrincipal>(userID); - - final PersonalDetails personalDetails = new PersonalDetails("cadc", "test"); - expected.details.add(personalDetails); + final User expected = new User(); + expected.personalDetails = new PersonalDetails("cadc", "test"); StringBuilder sb = new StringBuilder(); UserWriter userWriter = new UserWriter(); userWriter.write(expected, sb); String expectedUser = sb.toString(); - Set<PersonalDetails> details = expected.getDetails(PersonalDetails.class); - PersonalDetails pd = details.iterator().next(); - pd.city = "city"; - - expected.getIdentities().add(new NumericPrincipal(789)); + expected.personalDetails.city = "city"; + expected.getIdentities().add(userID); + expected.getIdentities().add(new NumericPrincipal(UUID.randomUUID())); expected.getIdentities().add(new X500Principal("cn=foo,o=bar")); - - final PosixDetails posixDetails = new PosixDetails(123L, 456L, "/dev/null"); - expected.details.add(posixDetails); + expected.posixDetails = new PosixDetails("username", 123L, 456L, "/dev/null"); final Writer writer = new StringWriter(); final PrintWriter printWriter = new PrintWriter(writer); @@ -249,7 +247,7 @@ public class GetUserActionTest testSubject.doAction(); String actualUser = writer.toString(); - + log.debug("expected:\n" + expectedUser); log.debug("actual:\n" + actualUser); @@ -261,19 +259,19 @@ public class GetUserActionTest @Test public void writeAugmentedUser() throws Exception { - final UserPersistence<Principal> mockUserPersistence = + final UserPersistence mockUserPersistence = createMock(UserPersistence.class); final HttpServletResponse mockResponse = createMock(HttpServletResponse.class); final HttpPrincipal userID = new HttpPrincipal("CADCtest"); final GetUserAction testSubject = new GetUserAction(userID, null); testSubject.userPersistence = mockUserPersistence; - testSubject.setAugmentUser(true); + testSubject.setIsPrivilegedUser(true); - final NumericPrincipal numericPrincipal = new NumericPrincipal(789); + final NumericPrincipal numericPrincipal = new NumericPrincipal(UUID.randomUUID()); final X500Principal x500Principal = new X500Principal("cn=foo,o=bar"); - final User<Principal> expected = new User<Principal>(userID); + final User expected = new User(); expected.getIdentities().add(userID); expected.getIdentities().add(numericPrincipal); expected.getIdentities().add(x500Principal); @@ -309,7 +307,7 @@ public class GetUserActionTest { final SyncOutput mockSyncOut = createMock(SyncOutput.class); - final UserPersistence<HttpPrincipal> mockUserPersistence = + final UserPersistence mockUserPersistence = createMock(UserPersistence.class); final HttpPrincipal userID = new HttpPrincipal("CADCtest"); @@ -318,7 +316,8 @@ public class GetUserActionTest testSubject.setAcceptedContentType(AbstractUserAction.JSON_CONTENT_TYPE); - final User<HttpPrincipal> user = new User<HttpPrincipal>(userID); + final User user = new User(); + user.getIdentities().add(userID); final Writer writer = new StringWriter(); final PrintWriter printWriter = new PrintWriter(writer); diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserListActionTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserListActionTest.java index e601f1007ab9beb3062167d2483071e6dc32ffde..b1c0edf1a443fd1b92b6b2068d18242a723d6dd9 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserListActionTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserListActionTest.java @@ -69,36 +69,33 @@ package ca.nrc.cadc.ac.server.web.users; -import ca.nrc.cadc.ac.PersonalDetails; -import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.ac.json.JsonUserListWriter; -import ca.nrc.cadc.ac.server.UserPersistence; -import ca.nrc.cadc.ac.server.web.SyncOutput; -import ca.nrc.cadc.ac.xml.UserListWriter; -import ca.nrc.cadc.auth.HttpPrincipal; -import org.apache.log4j.Level; - -import org.json.JSONArray; - -import ca.nrc.cadc.util.Log4jInit; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; -import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; -import java.security.Principal; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; - -import static org.easymock.EasyMock.*; +import org.apache.log4j.Level; import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.assertEquals; import org.skyscreamer.jsonassert.JSONAssert; +import ca.nrc.cadc.ac.PersonalDetails; +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.json.JsonUserListWriter; +import ca.nrc.cadc.ac.server.UserPersistence; +import ca.nrc.cadc.ac.server.web.SyncOutput; +import ca.nrc.cadc.ac.xml.UserListWriter; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.util.Log4jInit; + /** * * @author adriand @@ -117,15 +114,16 @@ public class GetUserListActionTest { final SyncOutput mockSyncOut = createMock(SyncOutput.class); - final UserPersistence<HttpPrincipal> mockUserPersistence = + final UserPersistence mockUserPersistence = createMock(UserPersistence.class); - List<User<Principal>> expectedUsers = new ArrayList<User<Principal>>(); + List<User> expectedUsers = new ArrayList<User>(); for (int i = 1; i <= 5; i++) { - User<Principal> user = new User<Principal>(new HttpPrincipal("USER_" + i)); + User user = new User(); + user.getIdentities().add(new HttpPrincipal("USER_" + i)); PersonalDetails pd = new PersonalDetails("USER", Integer.toString(i)); - user.details.add(pd); + user.personalDetails = pd; expectedUsers.add(user); } @@ -163,15 +161,16 @@ public class GetUserListActionTest { final SyncOutput mockSyncOut = createMock(SyncOutput.class); - final UserPersistence<HttpPrincipal> mockUserPersistence = + final UserPersistence mockUserPersistence = createMock(UserPersistence.class); - List<User<Principal>> expectedUsers = new ArrayList<User<Principal>>(); + List<User> expectedUsers = new ArrayList<User>(); for (int i = 1; i <= 5; i++) { - User<Principal> user = new User<Principal>(new HttpPrincipal("USER_" + i)); + User user = new User(); + user.getIdentities().add(new HttpPrincipal("USER_" + i)); PersonalDetails pd = new PersonalDetails("USER", Integer.toString(i)); - user.details.add(pd); + user.personalDetails = pd; expectedUsers.add(user); } diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/ModifyUserActionTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/ModifyUserActionTest.java index 1541ee59c0f8ce56c54dd165f904fe44a2846b23..a082d0012eb4aef6ffce3a9168c03c2cb98f7fea 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/ModifyUserActionTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/ModifyUserActionTest.java @@ -68,40 +68,38 @@ package ca.nrc.cadc.ac.server.web.users; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.Principal; + +import javax.servlet.http.HttpServletRequest; + +import org.easymock.EasyMock; +import org.junit.Test; + import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.json.JsonUserWriter; import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.ac.server.web.SyncOutput; import ca.nrc.cadc.auth.HttpPrincipal; -import org.easymock.EasyMock; -import org.junit.Test; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.net.URL; -import java.security.Principal; - -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; -import static org.junit.Assert.assertEquals; public class ModifyUserActionTest { @Test - public void run() throws Exception + public void testModifyUser() throws Exception { final HttpPrincipal httpPrincipal = new HttpPrincipal("CADCtest"); - User<Principal> expected = new User<Principal>(httpPrincipal); + User expected = new User(); expected.getIdentities().add(httpPrincipal); - final PersonalDetails pd = new PersonalDetails("CADC", "Test"); - pd.email = "CADC.Test@nrc-cnrc.gc.ca"; - expected.details.add(pd); + expected.personalDetails = new PersonalDetails("CADC", "Test"); + expected.personalDetails.email = "CADC.Test@nrc-cnrc.gc.ca"; final StringBuilder sb = new StringBuilder(); final JsonUserWriter userWriter = new JsonUserWriter(); @@ -111,14 +109,11 @@ public class ModifyUserActionTest final InputStream inputStream = new ByteArrayInputStream(input); // Should match the JSON above, without the e-mail modification. + final User testUser = new User(); Principal principal = new HttpPrincipal("CADCtest"); - final User<Principal> userObject = - new User<Principal>(principal); - userObject.getIdentities().add(principal); - final PersonalDetails personalDetail = - new PersonalDetails("CADC", "Test"); - personalDetail.email = "CADC.Test@nrc-cnrc.gc.ca"; - userObject.details.add(personalDetail); + testUser.getIdentities().add(principal); + testUser.personalDetails = new PersonalDetails("CADC", "Test"); + testUser.personalDetails.email = "CADC.Test@nrc-cnrc.gc.ca"; StringBuffer requestUrl = new StringBuffer(); requestUrl.append("http://host/ac/users/CADCtest?idType=HTTP"); @@ -129,16 +124,11 @@ public class ModifyUserActionTest EasyMock.expect(mockRequest.getContextPath()).andReturn("/ac").once(); EasyMock.expect(mockRequest.getServletPath()).andReturn("/users").once(); - final SyncOutput mockSyncOut = - createMock(SyncOutput.class); - @SuppressWarnings("unchecked") - final UserPersistence<Principal> mockUserPersistence = - createMock(UserPersistence.class); - - expect(mockUserPersistence.modifyUser(userObject)).andReturn( - userObject).once(); + final UserPersistence mockUserPersistence = createMock(UserPersistence.class); + expect(mockUserPersistence.modifyUser(testUser)).andReturn(testUser).once(); + final SyncOutput mockSyncOut = createMock(SyncOutput.class); mockSyncOut.setHeader("Location", requestUrl.toString()); expectLastCall().once(); diff --git a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java index 2f3ae849c27cb8387fc781c6ecb15e0d1d03ebb8..a705944eb520913f48b6135d09629181dbdb6ec5 100644 --- a/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java +++ b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java @@ -67,14 +67,16 @@ package ca.nrc.cadc.ac.server.web.users; -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; +import ca.nrc.cadc.util.Log4jInit; + public class UserActionFactoryTest { @@ -113,6 +115,7 @@ public class UserActionFactoryTest HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class); EasyMock.expect(request.getPathInfo()).andReturn("userName"); EasyMock.expect(request.getParameter("idType")).andReturn("sessionID"); + EasyMock.expect(request.getParameter("hard")).andReturn(null); EasyMock.replay(request); AbstractUserAction action = UserActionFactory.httpDeleteFactory().createAction(request); EasyMock.verify(request); diff --git a/cadcAccessControl/build.xml b/cadcAccessControl/build.xml index 99ec61e857e467f0a83eab0aa14e1b65fbfb7239..e8b0a8fd4bf74a1da01f1c623a60980315842510 100644 --- a/cadcAccessControl/build.xml +++ b/cadcAccessControl/build.xml @@ -123,7 +123,31 @@ <pathelement path="${build}/test/class"/> <pathelement path="${testingJars}"/> </classpath> - <test name="ca.nrc.cadc.ac.json.JsonGroupReaderWriterTest" /> + <!--<test name="ca.nrc.cadc.ac.client.GMSClientTest" />--> + <!--<test name="ca.nrc.cadc.ac.client.JsonUserListInputStreamWrapperTest" />--> + <!--<test name="ca.nrc.cadc.ac.client.UserClientTest" />--> + + <!--<test name="ca.nrc.cadc.ac.GroupPropertyTest" />--> + <!--<test name="ca.nrc.cadc.ac.GroupTest" />--> + <!--<test name="ca.nrc.cadc.ac.PersonalDetailsTest" />--> + <!--<test name="ca.nrc.cadc.ac.PosixDetailsTest" />--> + <!--<test name="ca.nrc.cadc.ac.RoleTest" />--> + <!--<test name="ca.nrc.cadc.ac.UserRequestTest" />--> + <test name="ca.nrc.cadc.ac.UserTest" /> + + <!--<test name="ca.nrc.cadc.ac.json.JsonGroupReaderWriterTest" />--> + <!--<test name="ca.nrc.cadc.ac.json.JsonUserReaderWriterTest" />--> + <!--<test name="ca.nrc.cadc.ac.json.JsonUserListReaderWriterTest" />--> + <!--<test name="ca.nrc.cadc.ac.json.JsonUserRequestReaderWriterTest" />--> + + <!--<test name="ca.nrc.cadc.ac.xml.GroupListReaderWriterTest" />--> + <!--<test name="ca.nrc.cadc.ac.xml.GroupPropertyReaderWriterTest" />--> + <!--<test name="ca.nrc.cadc.ac.xml.GroupReaderWriterTest" />--> + <!--<test name="ca.nrc.cadc.ac.xml.IdentityReaderWriterTest" />--> + <!--<test name="ca.nrc.cadc.ac.xml.UserDetailsReaderWriterTest" />--> + <!--<test name="ca.nrc.cadc.ac.xml.UserListReaderWriterTest" />--> + <!--<test name="ca.nrc.cadc.ac.xml.UserReaderWriterTest" />--> + <!--<test name="ca.nrc.cadc.ac.xml.UserRequestReaderWriterTest" />--> <formatter type="plain" usefile="false" /> </junit> </target> diff --git a/cadcAccessControl/doc/AccessControl.png b/cadcAccessControl/doc/AccessControl.0.1.png similarity index 100% rename from cadcAccessControl/doc/AccessControl.png rename to cadcAccessControl/doc/AccessControl.0.1.png diff --git a/cadcAccessControl/doc/AccessControl.0.2.png b/cadcAccessControl/doc/AccessControl.0.2.png new file mode 100644 index 0000000000000000000000000000000000000000..a6ef372be2240af84a6019fcdb628909226e9466 Binary files /dev/null and b/cadcAccessControl/doc/AccessControl.0.2.png differ diff --git a/cadcAccessControl/doc/auth.zargo b/cadcAccessControl/doc/auth.0.1.zargo similarity index 100% rename from cadcAccessControl/doc/auth.zargo rename to cadcAccessControl/doc/auth.0.1.zargo diff --git a/cadcAccessControl/doc/auth.0.2.zargo b/cadcAccessControl/doc/auth.0.2.zargo new file mode 100644 index 0000000000000000000000000000000000000000..7ec86a4433b212aed030d24bd53bbb3b71fcd90f Binary files /dev/null and b/cadcAccessControl/doc/auth.0.2.zargo differ diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/AC.java b/cadcAccessControl/src/ca/nrc/cadc/ac/AC.java index cacb9a00c2efacc78ee92aa9d23ed35449fe38d9..daa6a4ccf8041c18c0b6858d820f3c8a9747dfd6 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/AC.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/AC.java @@ -75,19 +75,23 @@ public class AC { // Denotes a description given to a group public static final String PROPERTY_GROUP_DESCRIPTION = "ivo://ivoa.net/gms#description"; - + // Denotes the DN of a group owner public static final String PROPERTY_OWNER_DN = "ivo://ivoa.net/gms#owner_dn"; - + // Denotes the DN of a user public static final String PROPERTY_USER_DN = "ivo://ivoa.net/gms#user_dn"; - + // Denotes a group readable by public public static final String PROPERTY_PUBLIC = "ivo://ivoa.net/gms#public"; - - public static final String GMS_SERVICE_URI = "ivo://cadc.nrc.ca/canfargms"; - + + public static final String UMS_SERVICE_URI = "ivo://canfar.net/ums"; + public static final String GMS_SERVICE_URI = "ivo://canfar.net/gms"; + // Group URI attribute once the group name is appended public static final String GROUP_URI = "ivo://cadc.nrc.ca/gms#"; - + + // User URI with appended UUID represents a unique user + public static final String USER_URI = "ivo://cadc.nrc.ca/user"; + } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/ActivatedGroup.java b/cadcAccessControl/src/ca/nrc/cadc/ac/ActivatedGroup.java index 22e445ede8750b77db6dd5f0bc07db03420531db..398efe920bb4cbe3832aae474eef77757ffb84d1 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/ActivatedGroup.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/ActivatedGroup.java @@ -69,11 +69,13 @@ package ca.nrc.cadc.ac; +import java.lang.reflect.Field; + public class ActivatedGroup extends Group { public ActivatedGroup(Group group) { - super(group.getID(), group.getOwner()); + super(group.getID()); this.description = group.description; this.properties = group.getProperties(); this.lastModified = group.lastModified; @@ -82,4 +84,5 @@ public class ActivatedGroup extends Group this.getUserAdmins().addAll(group.getUserAdmins()); this.getGroupAdmins().addAll(group.getGroupAdmins()); } + } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/Group.java b/cadcAccessControl/src/ca/nrc/cadc/ac/Group.java index 8dac1009e59bf92e492678dfb3837e7088aa0658..c775729a29e897f745627dccf05d339cd8b19f5e 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/Group.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/Group.java @@ -68,7 +68,6 @@ */ package ca.nrc.cadc.ac; -import java.security.Principal; import java.util.Date; import java.util.HashSet; import java.util.Set; @@ -76,56 +75,44 @@ import java.util.Set; public class Group { private String groupID; - - private User<? extends Principal> owner; - + + private User owner; + // group's properties protected Set<GroupProperty> properties = new HashSet<GroupProperty>(); // group's user members - private Set<User<? extends Principal>> userMembers = new HashSet<User<? extends Principal>>(); + private UserSet userMembers = new UserSet(); // group's group members private Set<Group> groupMembers = new HashSet<Group>(); - + // group's user admins - private Set<User<? extends Principal>> userAdmins = new HashSet<User<? extends Principal>>(); - + private UserSet userAdmins = new UserSet(); + // group's group admins private Set<Group> groupAdmins = new HashSet<Group>(); - + public String description; public Date lastModified; - public Group() {} - - /** - * Ctor. - * - * @param groupID Unique ID for the group. Must be a valid URI fragment - * component, so it's restricted to alphanumeric - * and "-", ".","_","~" characters. - */ - public Group(String groupID) + public Group() { - this(groupID, null); } /** * Ctor. - * - * @param groupID Unique ID for the group. Must be a valid URI fragment - * component, so it's restricted to alphanumeric + * + * @param groupID Unique ID for the group. Must be a valid URI fragment + * component, so it's restricted to alphanumeric * and "-", ".","_","~" characters. - * @param owner Owner/Creator of the group. */ - public Group(String groupID, User<? extends Principal> owner) + public Group(String groupID) { if (groupID == null) { - throw new IllegalArgumentException("Null groupID"); + throw new IllegalArgumentException("null groupID"); } - if (!groupID.matches("^[a-zA-Z0-9\\-\\.~_]*$")) { throw new IllegalArgumentException("Invalid group ID " + groupID + @@ -133,12 +120,11 @@ public class Group } this.groupID = groupID; - this.owner = owner; } /** * Obtain this Group's unique id. - * + * * @return String group ID. */ public String getID() @@ -150,18 +136,13 @@ public class Group * Obtain this group's owner * @return owner of the group */ - public User<? extends Principal> getOwner() + public User getOwner() { return owner; } - public void setOwner(User<? extends Principal> owner) - { - this.owner = owner; - } - /** - * + * * @return a set of properties associated with a group */ public Set<GroupProperty> getProperties() @@ -170,34 +151,34 @@ public class Group } /** - * + * * @return individual user members of this group */ - public Set<User<? extends Principal>> getUserMembers() + public UserSet getUserMembers() { return userMembers; } /** - * + * * @return group members of this group */ public Set<Group> getGroupMembers() { return groupMembers; } - + /** - * + * * @return individual user admins of this group */ - public Set<User<? extends Principal>> getUserAdmins() + public UserSet getUserAdmins() { return userAdmins; } /** - * + * * @return group admins of this group */ public Set<Group> getGroupAdmins() @@ -245,4 +226,5 @@ public class Group { return getClass().getSimpleName() + "[" + groupID + "]"; } + } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/GroupProperty.java b/cadcAccessControl/src/ca/nrc/cadc/ac/GroupProperty.java index 2c4c89aad4ddf08e1e14fcd59f39c3002f20f1ae..6d7f3486e72ab46553e39d3bc3435cffa6c4f264 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/GroupProperty.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/GroupProperty.java @@ -74,32 +74,6 @@ package ca.nrc.cadc.ac; */ public class GroupProperty { - /** - * Name of the GroupProperty element. - */ - public static final String NAME = "property"; - - /** - * Name of the property key attribute in the GroupProperty element. - */ - public static final String KEY_ATTRIBUTE = "key"; - - /** - * Name of the property type attribute in the GroupProperty element. - */ - public static final String TYPE_ATTRIBUTE = "type"; - - /** - * Name of the property readOnly attribute in the GroupProperty element. - */ - public static final String READONLY_ATTRIBUTE = "readOnly"; - - /** - * Allowed types. - */ - public static final String STRING_TYPE = "String"; - public static final String INTEGER_TYPE = "Integer"; - // The property identifier private String key; diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/InternalID.java b/cadcAccessControl/src/ca/nrc/cadc/ac/InternalID.java new file mode 100644 index 0000000000000000000000000000000000000000..187d881ad64c2b8c87de727c3fdf9cd98a957853 --- /dev/null +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/InternalID.java @@ -0,0 +1,191 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2016. (c) 2016. + * 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; + +import java.net.URI; +import java.util.UUID; + +/** + * Class that represents a numeric id. This is useful for + * representing an internal user key reference. + * + * The expected format of the URI is scheme://authority?uuid + */ +public class InternalID +{ + private URI uri; + private UUID uuid; + + /** + * Ctor + * @param uri unique identifier + */ + public InternalID(URI uri) + { + if (uri == null) + { + throw new IllegalArgumentException("uri is null"); + } + + if (uri.getFragment() != null) + { + throw new IllegalArgumentException("fragment not allowed"); + } + + this.uri = uri; + uuid = UUID.fromString(uri.getQuery()); + } + + /** + * Ctor + * @param uri unique identifier + * @param id The uuid of the identifier + */ + public InternalID(URI uri, UUID id) + { + if (uri == null) + { + throw new IllegalArgumentException("uri is null"); + } + + if (id == null) + { + throw new IllegalArgumentException("id is null"); + } + + if (uri.getQuery() != null) + { + throw new IllegalArgumentException("query not allowed in base uri"); + } + + if (uri.getFragment() != null) + { + throw new IllegalArgumentException("fragment not allowed"); + } + + this.uri = URI.create(uri.toASCIIString() + "?" + id.toString()); + this.uuid = id; + } + + public URI getURI() + { + return uri; + } + + public UUID getUUID() + { + return uuid; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() + { + int prime = 31; + int result = 1; + result = prime * result + uri.hashCode(); + return result; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (obj == null) + { + return false; + } + if (!(obj instanceof InternalID)) + { + return false; + } + InternalID other = (InternalID) obj; + if (uri.equals(other.uri)) + { + return true; + } + return false; + } + + @Override + public String toString() + { + return getClass().getSimpleName() + "[" + uri + "]"; + } + +} diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/PersonalDetails.java b/cadcAccessControl/src/ca/nrc/cadc/ac/PersonalDetails.java index 13c59dd482eea60478fb7ed58d5d27f40cca22cc..66dd4854bcdeaf701fb35402d51a4a58fc2c4539 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/PersonalDetails.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/PersonalDetails.java @@ -68,48 +68,8 @@ */ package ca.nrc.cadc.ac; -public class PersonalDetails implements UserDetails +public class PersonalDetails { - /** - * Name of the PersonalDetails element. - */ - public static final String NAME = "personalDetails"; - - /** - * Name of the firstName element. - */ - public static final String FIRSTNAME = "firstName"; - - /** - * Name of the lastName element. - */ - public static final String LASTNAME = "lastName"; - - /** - * Name of the email element. - */ - public static final String EMAIL = "email"; - - /** - * Name of the email element. - */ - public static final String ADDRESS = "address"; - - /** - * Name of the email element. - */ - public static final String INSTITUTE = "institute"; - - /** - * Name of the email element. - */ - public static final String CITY = "city"; - - /** - * Name of the email element. - */ - public static final String COUNTRY = "country"; - private String firstName; private String lastName; public String email; @@ -205,14 +165,14 @@ public class PersonalDetails implements UserDetails */ public String toStringFormatted() { - StringBuffer sb = new StringBuffer(NAME + "\n"); - sb.append(FIRSTNAME + ": " + firstName +"\n"); - sb.append(LASTNAME + ": " + lastName +"\n"); - sb.append(EMAIL + ": " + email +"\n"); - sb.append(ADDRESS + ": " + address +"\n"); - sb.append(INSTITUTE + ": " + institute +"\n"); - sb.append(CITY + ": " + city +"\n"); - sb.append(COUNTRY + ": " + country +"\n"); + StringBuffer sb = new StringBuffer("PersonalDetails" + "\n"); + sb.append("firstName" + ": " + firstName +"\n"); + sb.append("lastName" + ": " + lastName +"\n"); + sb.append("email" + ": " + email +"\n"); + sb.append("address" + ": " + address +"\n"); + sb.append("institute" + ": " + institute +"\n"); + sb.append("city" + ": " + city +"\n"); + sb.append("country" + ": " + country +"\n"); return sb.toString(); diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/PosixDetails.java b/cadcAccessControl/src/ca/nrc/cadc/ac/PosixDetails.java index af282d6d006b05657c490ea9944f31e2074adc0a..bc068919680f539c24ba2b79b5c5c594dc1d7952 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/PosixDetails.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/PosixDetails.java @@ -71,28 +71,9 @@ package ca.nrc.cadc.ac; /** * Represents the posix account details associated with a user account. */ -public class PosixDetails implements UserDetails +public class PosixDetails { - /** - * Name of the PosixDetails element. - */ - public static final String NAME = "posixDetails"; - - /** - * Name of the uid element. - */ - public static final String UID = "uid"; - - /** - * Name of the gid element. - */ - public static final String GID = "gid"; - - /** - * Name of the homeDirectory element. - */ - public static final String HOME_DIRECTORY = "homeDirectory"; - + private String username; private long uid; private long gid; private String homeDirectory; @@ -103,24 +84,36 @@ public class PosixDetails implements UserDetails public String loginShell; /** - * + * @param userName user name * @param uid posix uid * @param gid posix gid * @param homeDirectory home directory */ - public PosixDetails(long uid, long gid, String homeDirectory) + public PosixDetails(String username, long uid, long gid, String homeDirectory) { - this.uid = uid; - this.gid = gid; + if (username == null) + { + throw new IllegalArgumentException("username is null"); + } if (homeDirectory == null) { - throw new IllegalArgumentException( - "null home directory in POSIX details"); + throw new IllegalArgumentException("homeDirectory in null"); } + this.username = username; + this.uid = uid; + this.gid = gid; this.homeDirectory = homeDirectory; } + /** + * @return the username + */ + public String getUsername() + { + return username; + } + /** * @return the uid */ @@ -155,9 +148,10 @@ public class PosixDetails implements UserDetails { int prime = 31; int result = 1; + result = prime * result + username.hashCode(); + result = prime * result + (int) (uid ^ uid >>> 32); result = prime * result + (int) (gid ^ gid >>> 32); result = prime * result + homeDirectory.hashCode(); - result = prime * result + (int) (uid ^ uid >>> 32); return result; } @@ -182,6 +176,14 @@ public class PosixDetails implements UserDetails return false; } PosixDetails other = (PosixDetails) obj; + if (!username.equals(other.getUsername())) + { + return false; + } + if (uid != other.uid) + { + return false; + } if (gid != other.gid) { return false; @@ -197,7 +199,7 @@ public class PosixDetails implements UserDetails @Override public String toString() { - return getClass().getSimpleName() + "[" + uid + ", " + + return getClass().getSimpleName() + "[" + username + "," + uid + ", " + gid + ", " + homeDirectory + "]"; } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/ReaderException.java b/cadcAccessControl/src/ca/nrc/cadc/ac/ReaderException.java index 397d1e62113993fc59cee4f79bbf9a62ea27a62e..80ec4425ea05b4f96470fe1c72692cd5a88e784c 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/ReaderException.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/ReaderException.java @@ -68,12 +68,10 @@ */ package ca.nrc.cadc.ac; -import java.io.IOException; - /** * Class for all Exceptions that occur during reading. */ -public class ReaderException extends IOException +public class ReaderException extends Exception { /** * Constructs a new exception with the specified detail message. The diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/User.java b/cadcAccessControl/src/ca/nrc/cadc/ac/User.java index 289c5f2499d36a155ebeb8ba69ae358ecf2dfd92..607af355616f2134b3245dbcaad5059ed8f30a5a 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/User.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/User.java @@ -69,32 +69,43 @@ package ca.nrc.cadc.ac; import java.security.Principal; -import java.util.HashSet; +import java.util.Comparator; +import java.util.Date; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + import javax.security.auth.x500.X500Principal; -import ca.nrc.cadc.auth.AuthenticationUtil; -public class User<T extends Principal> +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.auth.PrincipalComparator; + +public class User { - private T userID; - - private Set<Principal> identities = new HashSet<Principal>(); + private InternalID id; + + private SortedSet<Principal> identities; + + public PersonalDetails personalDetails; + public PosixDetails posixDetails; + + public Date lastModified; - public Set<UserDetails> details = new HashSet<UserDetails>(); - /** * Applications can stash some extra stuff here. */ public Object appData; - - public User(final T userID) + + public User() { - if (userID == null) - { - throw new IllegalArgumentException("null userID"); - } - this.userID = userID; - identities.add(userID); + PrincipalComparator p = new PrincipalComparator(); + UserPrincipalComparator u = new UserPrincipalComparator(p); + this.identities = new TreeSet<Principal>(u); + } + + public InternalID getID() + { + return id; } public Set<Principal> getIdentities() @@ -102,114 +113,137 @@ public class User<T extends Principal> return identities; } - public T getUserID() + /** + * Obtain a set of identities whose type match the given one. + * + * @param identityClass The class to search on. + * @param <S> The Principal type. + * @return Set of matched identities, or empty Set. + * Never null. + */ + public <S extends Principal> Set<S> getIdentities(final Class<S> identityClass) { - return userID; + PrincipalComparator p = new PrincipalComparator(); + UserPrincipalComparator u = new UserPrincipalComparator(p); + final Set<S> matchedIdentities = new TreeSet<S>(u); + + for (final Principal principal : identities) + { + if (identityClass.isAssignableFrom(principal.getClass())) + { + matchedIdentities.add((S) principal); + } + } + + return matchedIdentities; } - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() + public HttpPrincipal getHttpPrincipal() { - int prime = 31; - int result = 1; - result = prime * result + userID.hashCode(); - return result; + Set<HttpPrincipal> identities = getIdentities(HttpPrincipal.class); + if (!identities.isEmpty()) + { + return identities.iterator().next(); + } + return null; } - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) + /** + * @deprecated */ - @Override - public boolean equals(Object obj) + public X500Principal getX500Principal() { - if (this == obj) + final Set<X500Principal> identities = + getIdentities(X500Principal.class); + if (!identities.isEmpty()) { - return true; + return identities.iterator().next(); } - if (obj == null) + return null; + } + + + /** + * A User is considered consistent if the User's set of identities are a superset + * of this Users set of identities. + * + * @param superset + * @return + */ + public boolean isConsistent(final User superset) + { + + if (superset == null) { return false; } - if (getClass() != obj.getClass()) + + if (this.identities.size() == 0 || superset.identities.size() == 0) { return false; } - final User other = (User) obj; - if (userID instanceof X500Principal) - { - return AuthenticationUtil.equals(userID, other.userID); - } - else - { - return userID.equals(other.userID); - } + PrincipalComparator p = new PrincipalComparator(); + TreeSet<Principal> set1 = new TreeSet<Principal>(p); + TreeSet<Principal> set2 = new TreeSet<Principal>(p); + set1.addAll(superset.getIdentities()); + set2.addAll(this.getIdentities()); + return set1.containsAll(set2); } + + /* + * @see java.lang.Object#equals(java.lang.Object) + */ @Override - public String toString() + public boolean equals(Object obj) { - return getClass().getSimpleName() + "[" + userID.getName() + "]"; + if (obj instanceof User) + { + User user = (User) obj; + return (this.isConsistent(user) || user.isConsistent(this)); + } + return false; } - public <S extends UserDetails>S getUserDetail(final Class<S> userDetailsClass) + @Override + public String toString() { - for (final UserDetails ud : details) + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append("["); + if (id != null) { - if (ud.getClass() == userDetailsClass) - { - return (S) ud; - } + sb.append(id); } - return null; + sb.append("]"); + return sb.toString(); } - public <S extends UserDetails> Set<S> getDetails( - final Class<S> userDetailsClass) + private class UserPrincipalComparator implements Comparator<Principal> { - final Set<S> matchedDetails = new HashSet<S>(); + private PrincipalComparator p; - for (final UserDetails ud : details) + UserPrincipalComparator(PrincipalComparator p) { - if (ud.getClass() == userDetailsClass) - { - // This casting shouldn't happen, but it's the only way to - // do this without a lot of work. - // jenkinsd 2014.09.26 - matchedDetails.add((S) ud); - } + this.p = p; } - return matchedDetails; - } - - /** - * Obtain a set of identities whose type match the given one. - * - * @param identityClass The class to search on. - * @param <S> The Principal type. - * @return Set of matched identities, or empty Set. - * Never null. - */ - public <S extends Principal> Set<S> getIdentities( - final Class<S> identityClass) - { - final Set<S> matchedIdentities = new HashSet<S>(); - - for (final Principal p : identities) + @Override + public int compare(Principal o1, Principal o2) { - if (p.getClass() == identityClass) + if (o1 == null || o2 == null) { - // This casting shouldn't happen, but it's the only way to - // do this without a lot of work. - // jenkinsd 2014.09.26 - matchedIdentities.add((S) p); + throw new IllegalArgumentException("Cannot compare null objects"); } - } - return matchedIdentities; + if (o1 instanceof HttpPrincipal && o2 instanceof HttpPrincipal) + { + return 0; + } + + return p.compare(o1, o2); + } } + } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/UserRequest.java b/cadcAccessControl/src/ca/nrc/cadc/ac/UserRequest.java index 664b18d2a99d3f39e2927e9e7e6e89986371d2b6..c4558235c85f9e3f53d3facfb4b99ca4b7632377 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/UserRequest.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/UserRequest.java @@ -69,14 +69,12 @@ package ca.nrc.cadc.ac; -import java.security.Principal; - -public class UserRequest<T extends Principal> +public class UserRequest { - private User<T> user; + private User user; private char[] password; - public UserRequest(final User<T> user, final char[] password) + public UserRequest(final User user, final char[] password) { if (user == null) { @@ -86,11 +84,15 @@ public class UserRequest<T extends Principal> { throw new IllegalArgumentException("null or empty password"); } + if (user.getIdentities().isEmpty()) + { + throw new IllegalArgumentException("user has no identities"); + } this.user = user; this.password = password; } - public User<T> getUser() + public User getUser() { return this.user; } @@ -109,20 +111,20 @@ public class UserRequest<T extends Principal> } @Override - public boolean equals(Object o) + public boolean equals(Object obj) { - if (this == o) + if (this == obj) { return true; } - if (o == null || getClass() != o.getClass()) + if (obj == null || getClass() != obj.getClass()) { return false; } - UserRequest<?> that = (UserRequest<?>) o; + UserRequest other = (UserRequest) obj; - return user.equals(that.user); + return user.equals(other.user); } @Override diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/UserSet.java b/cadcAccessControl/src/ca/nrc/cadc/ac/UserSet.java new file mode 100644 index 0000000000000000000000000000000000000000..925de85bf40414d4e8f3a4dc156f5968c84ac5b3 --- /dev/null +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/UserSet.java @@ -0,0 +1,163 @@ +package ca.nrc.cadc.ac; + +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * A custom set built on a list implementation. + * + * Ordering will not be deterministic as per the Set specification. + */ +public class UserSet implements Set<User> +{ + + private List<User> users; + + public UserSet() + { + users = new ArrayList<User>(); + } + + public User getUser(Principal identity) + { + User test = null; + for (User u : users) + { + test = new User(); + test.getIdentities().add(identity); + if (test.isConsistent(u)) + { + return u; + } + } + return null; + } + + public List<User> getUserList() + { + return users; + } + + @Override + public boolean add(User e) + { + if (!users.contains(e)) + { + users.add(e); + return true; + } + return false; + } + + @Override + public boolean addAll(Collection<? extends User> c) + { + Iterator<? extends User> i = c.iterator(); + boolean modified = false; + while (i.hasNext()) + { + if (this.add(i.next())) + { + modified = true; + } + } + return modified; + } + + @Override + public void clear() + { + users.clear(); + } + + @Override + public boolean contains(Object o) + { + return users.contains(o); + } + + @Override + public boolean containsAll(Collection<?> c) + { + return users.containsAll(c); + } + + @Override + public boolean isEmpty() + { + return users.isEmpty(); + } + + @Override + public Iterator<User> iterator() + { + return users.iterator(); + } + + @Override + public boolean remove(Object o) + { + if (users.contains(o)) + { + users.remove(o); + return true; + } + return false; + } + + @Override + public boolean removeAll(Collection<?> c) + { + Iterator<?> i = c.iterator(); + boolean modified = false; + while (i.hasNext()) + { + if (this.remove(i.next())) + { + modified = true; + } + } + return modified; + } + + @Override + public boolean retainAll(Collection<?> c) + { + Iterator<User> i = users.listIterator(); + boolean modified = false; + User next = null; + while (i.hasNext()) + { + next = i.next(); + if (!c.contains(next)) + { + i.remove(); + modified = true; + } + } + return modified; + } + + @Override + public int size() + { + return users.size(); + } + + @Override + public Object[] toArray() + { + return users.toArray(); + } + + @Override + public <T> T[] toArray(T[] a) + { + return users.toArray(a); + } + +} diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/WriterException.java b/cadcAccessControl/src/ca/nrc/cadc/ac/WriterException.java index 3bf5a2b87b05ce9cb0c2279cbf7ad72c466801d1..902d2911945c325545db5ee2d68958527a73b046 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/WriterException.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/WriterException.java @@ -68,12 +68,10 @@ */ package ca.nrc.cadc.ac; -import java.io.IOException; - /** * Base exception for all Writer class exceptions. */ -public class WriterException extends IOException +public class WriterException extends Exception { /** * Constructs a new exception with the specified detail message. The diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java b/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java index 4ac845aa57bf70c5653599aae8f7c5440a50a0c3..00ebbc9bae25af523b1510d43ad6080fbe9f540c 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java @@ -75,17 +75,15 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; -import java.net.MalformedURLException; import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.security.AccessControlContext; import java.security.AccessControlException; import java.security.AccessController; import java.security.Principal; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Set; import javax.net.ssl.HttpsURLConnection; @@ -98,11 +96,12 @@ import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupAlreadyExistsException; import ca.nrc.cadc.ac.GroupNotFoundException; import ca.nrc.cadc.ac.Role; -import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; +import ca.nrc.cadc.ac.WriterException; import ca.nrc.cadc.ac.xml.GroupListReader; import ca.nrc.cadc.ac.xml.GroupReader; import ca.nrc.cadc.ac.xml.GroupWriter; +import ca.nrc.cadc.auth.AuthMethod; import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.SSLUtil; @@ -125,17 +124,22 @@ public class GMSClient implements TransferListener { private static final Logger log = Logger.getLogger(GMSClient.class); + private static final String GROUPS = "groups"; + private static final String SEARCH = "search"; + // socket factory to use when connecting private SSLSocketFactory sslSocketFactory; private SSLSocketFactory mySocketFactory; - // client needs to know which servcie it is bound to and lookup - // endpoints using RegistryClient - private URI serviceURI; - - // storing baseURL is now considered bad form but fix is out of scope right now - private String baseURL; + private RegistryClient registryClient; + + private URI groupsURI; + private URI searchURI; + public GMSClient(URI serviceURI) + { + this(serviceURI, new RegistryClient()); + } /** * Slightly more complete constructor. Tests can override the @@ -146,57 +150,21 @@ public class GMSClient implements TransferListener */ public GMSClient(URI serviceURI, RegistryClient registryClient) { - try - { - URL base = registryClient.getServiceURL(serviceURI, "https"); - if (base == null) - throw new IllegalArgumentException("service not found with https access: " + serviceURI); - this.baseURL = base.toExternalForm(); - - log.debug("AC Service URI: " + this.baseURL); - } - catch(MalformedURLException ex) - { - throw new RuntimeException("BUG: failed to construct GMS base URL", ex); - } - } + if (serviceURI == null) + throw new IllegalArgumentException("invalid serviceURI: " + serviceURI); + if (serviceURI.getFragment() != null) + throw new IllegalArgumentException("invalid serviceURI (fragment not allowed): " + serviceURI); - public GMSClient(URI serviceURI) - { - this(serviceURI, new RegistryClient()); - } + this.registryClient = registryClient; - /** - * Constructor. - * - * @param baseURL The URL of the supporting access control web service - * obtained from the registry. - * @deprecated - */ - public GMSClient(String baseURL) - throws IllegalArgumentException - { - if (baseURL == null) - { - throw new IllegalArgumentException("baseURL is required"); - } try { - new URL(baseURL); - } - catch (MalformedURLException e) - { - throw new IllegalArgumentException("URL is malformed: " + - e.getMessage()); + this.groupsURI = new URI(serviceURI.toASCIIString() + "#" + GROUPS); + this.searchURI = new URI(serviceURI.toASCIIString() + "#" + SEARCH); } - - if (baseURL.endsWith("/")) + catch(URISyntaxException ex) { - this.baseURL = baseURL.substring(0, baseURL.length() - 1); - } - else - { - this.baseURL = baseURL; + throw new RuntimeException("BUG: failed to create standardID from serviceURI + fragment", ex); } } @@ -222,67 +190,6 @@ public class GMSClient implements TransferListener throw new UnsupportedOperationException("Not yet implemented"); } - /** - * Obtain all of the users as userID - name in JSON format. - * - * @return List of HTTP Principal users. - * @throws IOException Any errors in reading. - */ - public List<User<? extends Principal>> getDisplayUsers() throws IOException - { - final List<User<? extends Principal>> webUsers = - new ArrayList<User<? extends Principal>>(); - final HttpDownload httpDownload = - createDisplayUsersHTTPDownload(webUsers); - - httpDownload.setRequestProperty("Accept", "application/json"); - httpDownload.run(); - - final Throwable error = httpDownload.getThrowable(); - - if (error != null) - { - final String errMessage = error.getMessage(); - final int responseCode = httpDownload.getResponseCode(); - log.debug("getDisplayUsers response " + responseCode + ": " - + errMessage); - if ((responseCode == 401) || (responseCode == 403) - || (responseCode == -1)) - { - throw new AccessControlException(errMessage); - } - else if (responseCode == 400) - { - throw new IllegalArgumentException(errMessage); - } - else - { - throw new IOException("HttpResponse (" + responseCode + ") - " - + errMessage); - } - } - - log.debug("Content-Length: " + httpDownload.getContentLength()); - log.debug("Content-Type: " + httpDownload.getContentType()); - - return webUsers; - } - - - /** - * Create a new HTTPDownload instance. Testers can override as needed. - * - * @param webUsers The User objects. - * @return HttpDownload instance. Never null. - * @throws IOException Any writing/reading errors. - */ - HttpDownload createDisplayUsersHTTPDownload( - final List<User<? extends Principal>> webUsers) throws IOException - { - final URL usersListURL = new URL(this.baseURL + "/users"); - return new HttpDownload(usersListURL, - new JsonUserListInputStreamWrapper(webUsers)); - } /** * Create a new group. @@ -297,9 +204,9 @@ public class GMSClient implements TransferListener */ public Group createGroup(Group group) throws GroupAlreadyExistsException, AccessControlException, - UserNotFoundException, IOException + UserNotFoundException, WriterException, IOException { - URL createGroupURL = new URL(this.baseURL + "/groups"); + URL createGroupURL = registryClient.getServiceURL(groupsURI, "https", "", AuthMethod.CERT); log.debug("createGroupURL request to " + createGroupURL.toString()); // reset the state of the cache @@ -370,7 +277,8 @@ public class GMSClient implements TransferListener public Group getGroup(String groupName) throws GroupNotFoundException, AccessControlException, IOException { - URL getGroupURL = new URL(this.baseURL + "/groups/" + groupName); + + URL getGroupURL = registryClient.getServiceURL(groupsURI, "https", groupName, AuthMethod.CERT); log.debug("getGroup request to " + getGroupURL.toString()); ByteArrayOutputStream out = new ByteArrayOutputStream(); HttpDownload transfer = new HttpDownload(getGroupURL, out); @@ -424,7 +332,8 @@ public class GMSClient implements TransferListener public List<String> getGroupNames() throws AccessControlException, IOException { - final URL getGroupNamesURL = new URL(this.baseURL + "/groups"); + URL getGroupNamesURL = registryClient.getServiceURL(groupsURI, "https", "", AuthMethod.CERT); + log.debug("getGroupNames request to " + getGroupNamesURL.toString()); final List<String> groupNames = new ArrayList<String>(); @@ -498,9 +407,9 @@ public class GMSClient implements TransferListener */ public Group updateGroup(Group group) throws IllegalArgumentException, GroupNotFoundException, UserNotFoundException, - AccessControlException, IOException + AccessControlException, WriterException, IOException { - URL updateGroupURL = new URL(this.baseURL + "/groups/" + group.getID()); + URL updateGroupURL = registryClient.getServiceURL(groupsURI, "https", group.getID(), AuthMethod.CERT); log.debug("updateGroup request to " + updateGroupURL.toString()); // reset the state of the cache @@ -567,7 +476,7 @@ public class GMSClient implements TransferListener public void deleteGroup(String groupName) throws GroupNotFoundException, AccessControlException, IOException { - URL deleteGroupURL = new URL(this.baseURL + "/groups/" + groupName); + URL deleteGroupURL = registryClient.getServiceURL(groupsURI, "https", groupName, AuthMethod.CERT); log.debug("deleteGroup request to " + deleteGroupURL.toString()); // reset the state of the cache @@ -632,9 +541,9 @@ public class GMSClient implements TransferListener throws IllegalArgumentException, GroupNotFoundException, AccessControlException, IOException { - URL addGroupMemberURL = new URL(this.baseURL + "/groups/" + - targetGroupName + "/groupMembers/" + - groupMemberName); + + String path = targetGroupName + "/groupMembers/" + groupMemberName; + URL addGroupMemberURL = registryClient.getServiceURL(groupsURI, "https", path, AuthMethod.CERT); log.debug("addGroupMember request to " + addGroupMemberURL.toString()); // reset the state of the cache @@ -683,12 +592,17 @@ public class GMSClient implements TransferListener public void addUserMember(String targetGroupName, Principal userID) throws GroupNotFoundException, UserNotFoundException, AccessControlException, IOException { + if (targetGroupName == null) + throw new IllegalArgumentException("targetGroupName required"); + + if (userID == null) + throw new IllegalArgumentException("userID required"); + log.debug("addUserMember: " + targetGroupName + " + " + userID.getName()); String userIDType = AuthenticationUtil.getPrincipalType(userID); - URL addUserMemberURL = new URL(this.baseURL + "/groups/" + targetGroupName - + "/userMembers/" + NetUtil.encode(userID.getName()) - + "?idType=" + userIDType); + String path = targetGroupName + "/userMembers/" + NetUtil.encode(userID.getName()) + "?idType=" + userIDType; + URL addUserMemberURL = registryClient.getServiceURL(groupsURI, "https", path, AuthMethod.CERT); log.debug("addUserMember request to " + addUserMemberURL.toString()); @@ -741,9 +655,9 @@ public class GMSClient implements TransferListener String groupMemberName) throws GroupNotFoundException, AccessControlException, IOException { - URL removeGroupMemberURL = new URL(this.baseURL + "/groups/" + - targetGroupName + "/groupMembers/" + - groupMemberName); + + String path = targetGroupName + "/groupMembers/" + groupMemberName; + URL removeGroupMemberURL = registryClient.getServiceURL(groupsURI, "https", path, AuthMethod.CERT); log.debug("removeGroupMember request to " + removeGroupMemberURL.toString()); @@ -809,10 +723,8 @@ public class GMSClient implements TransferListener String userIDType = AuthenticationUtil.getPrincipalType(userID); log.debug("removeUserMember: " + targetGroupName + " - " + userID.getName() + " type: " + userIDType); - - URL removeUserMemberURL = new URL(this.baseURL + "/groups/" + targetGroupName - + "/userMembers/" + NetUtil.encode(userID.getName()) - + "?idType=" + userIDType); + String path = targetGroupName + "/userMembers/" + NetUtil.encode(userID.getName()) + "?idType=" + userIDType; + URL removeUserMemberURL = registryClient.getServiceURL(groupsURI, "https", path, AuthMethod.CERT); log.debug("removeUserMember: " + removeUserMemberURL.toString()); @@ -893,7 +805,7 @@ public class GMSClient implements TransferListener return getMemberships(null, role); } - + private List<Group> getMemberships(Principal ignore, Role role) throws UserNotFoundException, AccessControlException, IOException { @@ -916,17 +828,17 @@ public class GMSClient implements TransferListener //String id = userID.getName(); String roleString = role.getValue(); - StringBuilder searchGroupURL = new StringBuilder(this.baseURL); - searchGroupURL.append("/search?"); + StringBuilder searchGroupPath = new StringBuilder("?"); //searchGroupURL.append("ID=").append(NetUtil.encode(id)); //searchGroupURL.append("&IDTYPE=").append(NetUtil.encode(idType)); - searchGroupURL.append("&ROLE=").append(NetUtil.encode(roleString)); + searchGroupPath.append("&ROLE=").append(NetUtil.encode(roleString)); + + URL searchURL = registryClient.getServiceURL(searchURI, "https", searchGroupPath.toString(), AuthMethod.CERT); - log.debug("getMemberships request to " + searchGroupURL.toString()); + log.debug("getMemberships request to " + searchURL.toString()); ByteArrayOutputStream out = new ByteArrayOutputStream(); - URL url = new URL(searchGroupURL.toString()); - HttpDownload transfer = new HttpDownload(url, out); + HttpDownload transfer = new HttpDownload(searchURL, out); transfer.setSSLSocketFactory(getSSLSocketFactory()); transfer.run(); @@ -994,7 +906,6 @@ public class GMSClient implements TransferListener * identified by userID, is a member (of type role) of that group. * Return null otherwise. * - * @param userID Identifies the user. * @param groupName Identifies the group. * @param role The membership role to search. * @return The group or null of the user is not a member. @@ -1025,18 +936,18 @@ public class GMSClient implements TransferListener //String id = userID.getName(); String roleString = role.getValue(); - StringBuilder searchGroupURL = new StringBuilder(this.baseURL); - searchGroupURL.append("/search?"); + StringBuilder searchGroupPath = new StringBuilder("?"); //searchGroupURL.append("ID=").append(NetUtil.encode(id)); //searchGroupURL.append("&IDTYPE=").append(NetUtil.encode(idType)); - searchGroupURL.append("&ROLE=").append(NetUtil.encode(roleString)); - searchGroupURL.append("&GROUPID=").append(NetUtil.encode(groupName)); + searchGroupPath.append("&ROLE=").append(NetUtil.encode(roleString)); + searchGroupPath.append("&GROUPID=").append(NetUtil.encode(groupName)); - log.debug("getMembership request to " + searchGroupURL.toString()); + URL searchURL = registryClient.getServiceURL(searchURI, "https", searchGroupPath.toString(), AuthMethod.CERT); + + log.debug("getMembership request to " + searchURL.toString()); ByteArrayOutputStream out = new ByteArrayOutputStream(); - URL url = new URL(searchGroupURL.toString()); - HttpDownload transfer = new HttpDownload(url, out); + HttpDownload transfer = new HttpDownload(searchURL, out); transfer.setSSLSocketFactory(getSSLSocketFactory()); transfer.run(); @@ -1103,15 +1014,15 @@ public class GMSClient implements TransferListener { return isMember(groupName, Role.MEMBER); } - + /** - * + * * @param groupName * @param role * @return * @throws UserNotFoundException * @throws AccessControlException - * @throws IOException + * @throws IOException */ public boolean isMember(String groupName, Role role) throws UserNotFoundException, AccessControlException, IOException @@ -1189,7 +1100,7 @@ public class GMSClient implements TransferListener Set<GroupMemberships> gset = subject.getPrivateCredentials(GroupMemberships.class); if (gset == null || gset.isEmpty()) { - GroupMemberships mems = new GroupMemberships(new User(userID)); + GroupMemberships mems = new GroupMemberships(userID); subject.getPrivateCredentials().add(mems); return mems; } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClientMain.java b/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClientMain.java index 19e7935c46fa846fa20422ee91a8256a9ed91551..dafea22126a0a497bcafb2593ac84219f2ff64e8 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClientMain.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClientMain.java @@ -249,10 +249,8 @@ public class GMSClientMain implements PrivilegedAction<Object> Group cur = client.getGroup(group); boolean update = true; - Iterator<User<? extends Principal>> iter = cur.getUserAdmins().iterator(); - while (iter.hasNext()) + for (User admin : cur.getUserAdmins()) { - User<? extends Principal> admin = iter.next(); for (Principal p : admin.getIdentities()) { if (p instanceof HttpPrincipal) @@ -266,9 +264,12 @@ public class GMSClientMain implements PrivilegedAction<Object> } } } + if (update) - { - cur.getUserAdmins().add(new User(hp)); + { + User adminUser = new User(); + adminUser.getIdentities().add(hp); + cur.getUserAdmins().add(adminUser); client.updateGroup(cur); log.info("admin added: " + userID); } @@ -288,10 +289,10 @@ public class GMSClientMain implements PrivilegedAction<Object> Group cur = client.getGroup(group); boolean update = false; - Iterator<User<? extends Principal>> iter = cur.getUserAdmins().iterator(); + Iterator<User> iter = cur.getUserAdmins().iterator(); while (iter.hasNext()) { - User<? extends Principal> admin = iter.next(); + User admin = iter.next(); for (Principal p : admin.getIdentities()) { if (p instanceof HttpPrincipal) @@ -325,8 +326,11 @@ public class GMSClientMain implements PrivilegedAction<Object> Set<X500Principal> principals = subject.getPrincipals(X500Principal.class); X500Principal p = principals.iterator().next(); - Group g = new Group(group, new User<X500Principal>(p)); - g.getUserMembers().add(g.getOwner()); + Group g = new Group(group); + + User member = new User(); + member.getIdentities().add(p); + g.getUserMembers().add(member); client.createGroup(g); } else if (command.equals(ARG_GET_GROUP)) diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/client/GroupMemberships.java b/cadcAccessControl/src/ca/nrc/cadc/ac/client/GroupMemberships.java index 910f27b50547652a2ec9079aa926526eda59e9df..9ea1293305256dc77806b7d3291767032ed70ed0 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/client/GroupMemberships.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/client/GroupMemberships.java @@ -69,15 +69,15 @@ package ca.nrc.cadc.ac.client; - import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.Role; -import ca.nrc.cadc.ac.User; +import org.apache.log4j.Logger; + +import java.security.Principal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.log4j.Logger; /** * Class used to hold list of groups in which a user is known to be a member. @@ -88,15 +88,15 @@ public class GroupMemberships implements Comparable { private static final Logger log = Logger.getLogger(GroupMemberships.class); - private User user; + private Principal userID; private Map<Role, List<Group>> memberships = new HashMap<Role, List<Group>>(); private Map<Role, Boolean> complete = new HashMap<Role, Boolean>(); public GroupMemberships() { init(); } - public GroupMemberships(User user) + public GroupMemberships(Principal userID) { - this.user = user; + this.userID = userID; init(); } @@ -119,9 +119,9 @@ public class GroupMemberships implements Comparable } } - public User getUser() + public Principal getUserID() { - return user; + return userID; } public void add(Group group, Role role) diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapper.java b/cadcAccessControl/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapper.java index 484871bc0978aa4285793eeaa7f95191902e3c87..960b09eb1ac28831c92878661066be23ff76262d 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapper.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapper.java @@ -68,28 +68,24 @@ package ca.nrc.cadc.ac.client; +import ca.nrc.cadc.ac.ReaderException; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.json.JsonUserListReader; import ca.nrc.cadc.net.InputStreamWrapper; import java.io.IOException; import java.io.InputStream; -import java.security.Principal; import java.util.List; - public class JsonUserListInputStreamWrapper implements InputStreamWrapper { - private final List<User<? extends Principal>> output; - + private final List<User> output; - public JsonUserListInputStreamWrapper( - final List<User<? extends Principal>> output) + public JsonUserListInputStreamWrapper(final List<User> output) { this.output = output; } - /** * Read the stream in. * @@ -97,10 +93,19 @@ public class JsonUserListInputStreamWrapper implements InputStreamWrapper * @throws IOException Any reading exceptions. */ @Override - public void read(final InputStream inputStream) throws IOException + public void read(final InputStream inputStream) + throws IOException { final JsonUserListReader reader = new JsonUserListReader(); - output.addAll(reader.read(inputStream)); + try + { + output.addAll(reader.read(inputStream)); + } + catch (ReaderException e) + { + throw new IOException("Unable to parse input", e); + } } + } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/client/UserClient.java b/cadcAccessControl/src/ca/nrc/cadc/ac/client/UserClient.java index 4abb1807855b5bd2c9f68d366ed3be7c48ed3434..2ec7944f777c2dd97f0e5ede9335fd1ec80710e9 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/client/UserClient.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/client/UserClient.java @@ -68,10 +68,17 @@ */ package ca.nrc.cadc.ac.client; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; +import java.security.AccessControlException; import java.security.Principal; +import java.util.ArrayList; +import java.util.List; import java.util.Set; import javax.security.auth.Subject; @@ -79,12 +86,20 @@ import javax.security.auth.x500.X500Principal; import org.apache.log4j.Logger; +import ca.nrc.cadc.ac.ReaderException; import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserAlreadyExistsException; +import ca.nrc.cadc.ac.UserNotFoundException; +import ca.nrc.cadc.ac.WriterException; import ca.nrc.cadc.ac.xml.UserReader; +import ca.nrc.cadc.ac.xml.UserWriter; +import ca.nrc.cadc.auth.AuthMethod; import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.net.HttpDownload; +import ca.nrc.cadc.net.HttpUpload; import ca.nrc.cadc.net.NetUtil; +import ca.nrc.cadc.reg.client.RegistryClient; /** @@ -95,39 +110,46 @@ public class UserClient { private static final Logger log = Logger.getLogger(UserClient.class); - // socket factory to use when connecting - private String baseURL; + private static final String USERS = "users"; + private static final String USER_REQUESTS = "reqs"; + + private RegistryClient registryClient; + + private URI usersURI; + + // to be used when the client can work with + // user requests + private URI userReqsURI; /** * Constructor. * - * @param baseURL The URL of the supporting access control web service - * obtained from the registry. + * @param serviceURI The URI of the supporting access control web service + * obtained from the registry. */ - public UserClient(final String baseURL) + public UserClient(URI serviceURI) throws IllegalArgumentException { - if (baseURL == null) - { - throw new IllegalArgumentException("baseURL is required"); - } - try - { - new URL(baseURL); - } - catch (MalformedURLException e) - { - throw new IllegalArgumentException("URL is malformed: " + - e.getMessage()); - } + this(serviceURI, new RegistryClient()); + } + + public UserClient(URI serviceURI, RegistryClient registryClient) + { + if (serviceURI == null) + throw new IllegalArgumentException("Service URI cannot be null."); + if (serviceURI.getFragment() != null) + throw new IllegalArgumentException("invalid serviceURI (fragment not allowed): " + serviceURI); - if (baseURL.endsWith("/")) + this.registryClient = registryClient; + + try { - this.baseURL = baseURL.substring(0, baseURL.length() - 1); + this.usersURI = new URI(serviceURI.toASCIIString() + "#" + USERS); + this.userReqsURI = new URI(serviceURI.toASCIIString() + "#" + USER_REQUESTS); } - else + catch(URISyntaxException ex) { - this.baseURL = baseURL; + throw new RuntimeException("BUG: failed to create standardID from serviceURI + fragment", ex); } } @@ -137,16 +159,26 @@ public class UserClient * associated principals which are then added to the subject. * * @param subject The Subject to pull Princials for. + * @throws MalformedURLException */ - public void augmentSubject(Subject subject) + public void augmentSubject(Subject subject) throws MalformedURLException { Principal principal = this.getPrincipal(subject); if (principal != null) { - URL url = this.getURL(principal); - log.debug("augmentSubject request to " + url.toString()); + + String userID = principal.getName(); + String path = NetUtil.encode(userID) + "?idType=" + this.getIdType(principal) + "&detail=identity"; + + // augment subject calls are always https with client certs + URL getUserURL = registryClient.getServiceURL(usersURI, "https", path, AuthMethod.CERT); + + if (getUserURL == null) + throw new IllegalArgumentException("No service endpoint for uri " + usersURI); + + log.debug("augmentSubject request to " + getUserURL.toString()); ByteArrayOutputStream out = new ByteArrayOutputStream(); - HttpDownload download = new HttpDownload(url, out); + HttpDownload download = new HttpDownload(getUserURL, out); download.run(); int responseCode = download.getResponseCode(); @@ -169,7 +201,179 @@ public class UserClient } } + /** + * Obtain all of the users as userID - name in JSON format. + * + * @return List of HTTP Principal users. + * @throws IOException Any errors in reading. + */ + public List<User> getDisplayUsers() throws IOException + { + URL usersURL = registryClient.getServiceURL(usersURI, "https"); + final List<User> webUsers = new ArrayList<User>(); + HttpDownload httpDownload = + new HttpDownload(usersURL, + new JsonUserListInputStreamWrapper(webUsers)); + httpDownload.setRequestProperty("Accept", "application/json"); + httpDownload.run(); + + final Throwable error = httpDownload.getThrowable(); + + if (error != null) + { + final String errMessage = error.getMessage(); + final int responseCode = httpDownload.getResponseCode(); + log.debug("getDisplayUsers response " + responseCode + ": " + + errMessage); + if ((responseCode == 401) || (responseCode == 403) + || (responseCode == -1)) + { + throw new AccessControlException(errMessage); + } + else if (responseCode == 400) + { + throw new IllegalArgumentException(errMessage); + } + else + { + throw new IOException("HttpResponse (" + responseCode + ") - " + + errMessage); + } + } + + log.debug("Content-Length: " + httpDownload.getContentLength()); + log.debug("Content-Type: " + httpDownload.getContentType()); + + return webUsers; + } + + /** + * Create an auto-approved user directly in the user tree (not + * the userRequest tree) from the principal. + * + * @param principal Their x500 Principal + * @throws UserAlreadyExistsException + * @throws WriterException + * @throws IOException + * @throws URISyntaxException + * @throws ReaderException + */ + public User createUser(Principal principal) + throws UserAlreadyExistsException, IOException, WriterException, + ReaderException, URISyntaxException + { + if (principal == null) + { + throw new IllegalArgumentException("principal required"); + } + + User user = new User(); + user.getIdentities().add(principal); + UserWriter userWriter = new UserWriter(); + StringBuilder userXML = new StringBuilder(); + userWriter.write(user, userXML); + + URL createUserURL = registryClient.getServiceURL(usersURI, "https", null, AuthMethod.CERT); + + if (createUserURL == null) + throw new IllegalArgumentException("No service endpoint for uri " + usersURI); + log.debug("createUser request to " + createUserURL.toString()); + + ByteArrayInputStream in = new ByteArrayInputStream(userXML.toString().getBytes()); + HttpUpload put = new HttpUpload(in, createUserURL); + + put.run(); + int responseCode = put.getResponseCode(); + + if (responseCode == 200 || responseCode == 201) + { + try + { + return getUser(principal); + } + catch (UserNotFoundException e) + { + log.error("user created but not found", e); + // should not happen + throw new IllegalStateException("user created but not found", e); + } + } + + String message = ""; + if (put.getThrowable() != null) + { + log.debug("error calling createX509User", put.getThrowable()); + message = put.getThrowable().getMessage(); + } + + if (responseCode == 400) + { + throw new IllegalArgumentException(message); + } + if (responseCode == 409) // conflict + { + throw new UserAlreadyExistsException(message); + } + if (responseCode == 403) + { + throw new AccessControlException(message); + } + throw new IllegalStateException(message); + } + + /** + * Given a pricipal return the user object. + * + * @param principal The principal to lookup. + * @throws URISyntaxException + * @throws IOException + * @throws ReaderException + * @throws UserNotFoundException + */ + public User getUser(Principal principal) + throws ReaderException, IOException, URISyntaxException, UserNotFoundException + { + String id = NetUtil.encode(principal.getName()); + String path = "/" + id + "?idType=" + AuthenticationUtil.getPrincipalType(principal); + + URL getUserURL = registryClient.getServiceURL(usersURI, "https", path, AuthMethod.CERT); + if (getUserURL == null) + throw new IllegalArgumentException("No service endpoint for uri " + usersURI); + log.debug("getUser request to " + getUserURL.toString()); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + HttpDownload get = new HttpDownload(getUserURL, out); + + get.run(); + int responseCode = get.getResponseCode(); + + if (responseCode == 200) + { + UserReader userReader = new UserReader(); + return userReader.read(out.toString()); + } + + String message = ""; + if (get.getThrowable() != null) + { + log.debug("error calling get user", get.getThrowable()); + message = get.getThrowable().getMessage(); + } + if (responseCode == 400) + { + throw new IllegalArgumentException(message); + } + if (responseCode == 404) + { + throw new UserNotFoundException(message); + } + if (responseCode == 403) + { + throw new AccessControlException(message); + } + throw new IllegalStateException(message); + } protected Principal getPrincipal(final Subject subject) { @@ -208,7 +412,7 @@ public class UserClient String userXML = new String(out.toByteArray(), "UTF-8"); log.debug("userXML Input to getPrincipals(): " + userXML); - User<Principal> user = new UserReader().read(userXML); + User user = new UserReader().read(userXML); return user.getIdentities(); } catch (Exception e) @@ -217,24 +421,6 @@ public class UserClient } } - protected URL getURL(Principal principal) - { - try - { - String userID = principal.getName(); - URL url = new URL(this.baseURL + "/users/" + NetUtil.encode(userID) + - "?idType=" + this.getIdType(principal) + "&detail=identity"); - log.debug("getURL(): returned url =" - + "" - + " " + url.toString()); - return url; - } - catch (MalformedURLException e) - { - throw new RuntimeException(e); - } - } - protected String getIdType(Principal principal) { String idTypeStr = AuthenticationUtil.getPrincipalType(principal); diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonGroupReader.java b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonGroupReader.java index e5997162863ce13b0f560bb579d4b7e492d8b851..4092f11d6ba70127aa63298baccfddb0bed30b93 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonGroupReader.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonGroupReader.java @@ -108,13 +108,12 @@ public class JsonGroupReader extends GroupReader try { JsonInputter jsonInputter = new JsonInputter(); - jsonInputter.getListElementMap().put("identities", "identity"); - jsonInputter.getListElementMap().put("properties", "property"); - jsonInputter.getListElementMap().put("details", "userDetails"); - jsonInputter.getListElementMap().put("groupMembers", "group"); - jsonInputter.getListElementMap().put("groupAdmins", "group"); - jsonInputter.getListElementMap().put("userMembers", "user"); - jsonInputter.getListElementMap().put("userAdmins", "user"); + jsonInputter.getListElementMap().put(IDENTITIES, IDENTITY); + jsonInputter.getListElementMap().put(PROPERTIES, PROPERTY); + jsonInputter.getListElementMap().put(GROUP_MEMBERS, GROUP); + jsonInputter.getListElementMap().put(GROUP_ADMINS, GROUP); + jsonInputter.getListElementMap().put(USER_MEMBERS, USER); + jsonInputter.getListElementMap().put(USER_ADMINS, USER); Document document = jsonInputter.input(json); return getGroup(document.getRootElement()); diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonGroupWriter.java b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonGroupWriter.java index fff60d3f293d1059e993071ce77a5974d5fdc236..baabb78f1aa8c864a7e0b32693620108ac6cce39 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonGroupWriter.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonGroupWriter.java @@ -92,7 +92,8 @@ public class JsonGroupWriter extends GroupWriter * @throws WriterException */ @Override - public void write(Group group, Writer writer) throws IOException + public void write(Group group, Writer writer) + throws WriterException, IOException { if (group == null) { @@ -104,15 +105,14 @@ public class JsonGroupWriter extends GroupWriter document.setRootElement(groupElement); JsonOutputter jsonOutputter = new JsonOutputter(); - jsonOutputter.getListElementNames().add("groups"); - jsonOutputter.getListElementNames().add("users"); - jsonOutputter.getListElementNames().add("identities"); - jsonOutputter.getListElementNames().add("details"); - jsonOutputter.getListElementNames().add("properties"); - jsonOutputter.getListElementNames().add("groupMembers"); - jsonOutputter.getListElementNames().add("groupAdmins"); - jsonOutputter.getListElementNames().add("userMembers"); - jsonOutputter.getListElementNames().add("userAdmins"); + jsonOutputter.getListElementNames().add(GROUPS); + jsonOutputter.getListElementNames().add(USERS); + jsonOutputter.getListElementNames().add(IDENTITIES); + jsonOutputter.getListElementNames().add(PROPERTIES); + jsonOutputter.getListElementNames().add(GROUP_MEMBERS); + jsonOutputter.getListElementNames().add(GROUP_ADMINS); + jsonOutputter.getListElementNames().add(USER_MEMBERS); + jsonOutputter.getListElementNames().add(USER_ADMINS); jsonOutputter.output(document, writer); } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserListReader.java b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserListReader.java index f10740cb3aca9db42229e55fd5634d636dd89dc0..458335e039bbcf4e57d21dda443056e8f3a02b8c 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserListReader.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserListReader.java @@ -76,7 +76,6 @@ import org.jdom2.Document; import org.json.JSONException; import java.io.Reader; -import java.security.Principal; import java.util.List; import java.util.Scanner; @@ -94,7 +93,7 @@ public class JsonUserListReader extends UserListReader * @throws ReaderException */ @Override - public List<User<Principal>> read(Reader reader) + public List<User> read(Reader reader) throws ReaderException { if (reader == null) @@ -108,9 +107,8 @@ public class JsonUserListReader extends UserListReader try { JsonInputter jsonInputter = new JsonInputter(); - jsonInputter.getListElementMap().put("identities", "identity"); - jsonInputter.getListElementMap().put("details", "userDetails"); - jsonInputter.getListElementMap().put("users", "user"); + jsonInputter.getListElementMap().put(IDENTITIES, IDENTITY); + jsonInputter.getListElementMap().put(USERS, USER); Document document = jsonInputter.input(json); return getUserList(document.getRootElement()); diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserListWriter.java b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserListWriter.java index 0cb0b257ee9b433e7a43207360390e9577cf18fa..3771eef3c149fea587c88ad4383e5d4c53c75e79 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserListWriter.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserListWriter.java @@ -93,8 +93,8 @@ public class JsonUserListWriter extends UserListWriter * @throws IOException if the writer fails to write. */ @Override - public <T extends Principal> void write(Collection<User<T>> users, Writer writer) - throws IOException + public <T extends Principal> void write(Collection<User> users, Writer writer) + throws WriterException, IOException { if (users == null) { @@ -106,10 +106,9 @@ public class JsonUserListWriter extends UserListWriter document.setRootElement(usersElement); JsonOutputter jsonOutputter = new JsonOutputter(); - jsonOutputter.getListElementNames().add("groups"); - jsonOutputter.getListElementNames().add("users"); - jsonOutputter.getListElementNames().add("identities"); - jsonOutputter.getListElementNames().add("details"); + jsonOutputter.getListElementNames().add(GROUPS); + jsonOutputter.getListElementNames().add(USERS); + jsonOutputter.getListElementNames().add(IDENTITIES); jsonOutputter.output(document, writer); } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserReader.java b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserReader.java index 4ef9ee9afa59ff7ea34631b2f569fcc5c718644f..046def21f4b9e2eecb3ff86bc169d7b5bdf2fb92 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserReader.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserReader.java @@ -77,7 +77,6 @@ import org.json.JSONException; import java.io.IOException; import java.io.Reader; -import java.security.Principal; import java.util.Scanner; /** @@ -94,8 +93,8 @@ public class JsonUserReader extends UserReader * @throws IOException */ @Override - public User<Principal> read(Reader reader) - throws IOException + public User read(Reader reader) + throws ReaderException, IOException { if (reader == null) { @@ -108,8 +107,7 @@ public class JsonUserReader extends UserReader try { JsonInputter jsonInputter = new JsonInputter(); - jsonInputter.getListElementMap().put("identities", "identity"); - jsonInputter.getListElementMap().put("details", "userDetails"); + jsonInputter.getListElementMap().put(IDENTITIES, IDENTITY); Document document = jsonInputter.input(json); return getUser(document.getRootElement()); diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserRequestReader.java b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserRequestReader.java index eb03dbb01e2655358798886e44be0d896b867d9e..0059dc1e7f55862b4130942b102f12ae3b46f63a 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserRequestReader.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserRequestReader.java @@ -77,7 +77,6 @@ import org.json.JSONException; import java.io.IOException; import java.io.Reader; -import java.security.Principal; import java.util.Scanner; /** @@ -94,8 +93,8 @@ public class JsonUserRequestReader extends UserRequestReader * @throws IOException */ @Override - public UserRequest<Principal> read(Reader reader) - throws IOException + public UserRequest read(Reader reader) + throws ReaderException, IOException { if (reader == null) { @@ -108,8 +107,7 @@ public class JsonUserRequestReader extends UserRequestReader try { JsonInputter jsonInputter = new JsonInputter(); - jsonInputter.getListElementMap().put("identities", "identity"); - jsonInputter.getListElementMap().put("details", "userDetails"); + jsonInputter.getListElementMap().put(IDENTITIES, IDENTITY); Document document = jsonInputter.input(json); return getUserRequest(document.getRootElement()); diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserRequestWriter.java b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserRequestWriter.java index fdf5cbd835c50dc734f970c3880db72dcdc05fa9..257b4a91ecf3203b7bdaf8f547963722b07793a7 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserRequestWriter.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserRequestWriter.java @@ -78,7 +78,6 @@ import org.jdom2.Element; import java.io.IOException; import java.io.Writer; -import java.security.Principal; /** * Class to write a JSON representation of a UserRequest object. @@ -94,8 +93,8 @@ public class JsonUserRequestWriter extends UserRequestWriter * @throws WriterException */ @Override - public <T extends Principal> void write(UserRequest<T> userRequest, Writer writer) - throws IOException + public void write(UserRequest userRequest, Writer writer) + throws WriterException, IOException { if (userRequest == null) { @@ -107,15 +106,14 @@ public class JsonUserRequestWriter extends UserRequestWriter document.setRootElement(userRequestElement); JsonOutputter jsonOutputter = new JsonOutputter(); - jsonOutputter.getListElementNames().add("groups"); - jsonOutputter.getListElementNames().add("users"); - jsonOutputter.getListElementNames().add("identities"); - jsonOutputter.getListElementNames().add("details"); - jsonOutputter.getListElementNames().add("properties"); - jsonOutputter.getListElementNames().add("groupMembers"); - jsonOutputter.getListElementNames().add("groupAdmins"); - jsonOutputter.getListElementNames().add("userMembers"); - jsonOutputter.getListElementNames().add("userAdmins"); + jsonOutputter.getListElementNames().add(GROUPS); + jsonOutputter.getListElementNames().add(USERS); + jsonOutputter.getListElementNames().add(IDENTITIES); + jsonOutputter.getListElementNames().add(PROPERTIES); + jsonOutputter.getListElementNames().add(GROUP_MEMBERS); + jsonOutputter.getListElementNames().add(GROUP_ADMINS); + jsonOutputter.getListElementNames().add(USER_MEMBERS); + jsonOutputter.getListElementNames().add(USER_ADMINS); jsonOutputter.output(document, writer); } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserWriter.java b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserWriter.java index 3c05ad65f29861741c0b70f9e5ed6775bf624e97..80659443093260b31e767bde398b8233f0a068b0 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserWriter.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/json/JsonUserWriter.java @@ -77,7 +77,6 @@ import org.jdom2.Element; import java.io.IOException; import java.io.Writer; -import java.security.Principal; /** * Class to write a JSON representation of a User object. @@ -93,8 +92,8 @@ public class JsonUserWriter extends UserWriter * @throws WriterException */ @Override - public<T extends Principal> void write(User<T> user, Writer writer) - throws IOException + public void write(User user, Writer writer) + throws WriterException, IOException { if (user == null) { @@ -106,15 +105,14 @@ public class JsonUserWriter extends UserWriter document.setRootElement(userElement); JsonOutputter jsonOutputter = new JsonOutputter(); - jsonOutputter.getListElementNames().add("groups"); - jsonOutputter.getListElementNames().add("users"); - jsonOutputter.getListElementNames().add("identities"); - jsonOutputter.getListElementNames().add("details"); - jsonOutputter.getListElementNames().add("properties"); - jsonOutputter.getListElementNames().add("groupMembers"); - jsonOutputter.getListElementNames().add("groupAdmins"); - jsonOutputter.getListElementNames().add("userMembers"); - jsonOutputter.getListElementNames().add("userAdmins"); + jsonOutputter.getListElementNames().add(GROUPS); + jsonOutputter.getListElementNames().add(USERS); + jsonOutputter.getListElementNames().add(IDENTITIES); + jsonOutputter.getListElementNames().add(PROPERTIES); + jsonOutputter.getListElementNames().add(GROUP_MEMBERS); + jsonOutputter.getListElementNames().add(GROUP_ADMINS); + jsonOutputter.getListElementNames().add(USER_MEMBERS); + jsonOutputter.getListElementNames().add(USER_ADMINS); jsonOutputter.output(document, writer); } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java index 7deb29d40b2c696c7a1af07a64f1520ddd559f7a..242f0456561a587853843100ccc0fcb74b30d21a 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java @@ -72,21 +72,19 @@ package ca.nrc.cadc.ac.xml; import ca.nrc.cadc.ac.AC; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupProperty; +import ca.nrc.cadc.ac.InternalID; import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.PosixDetails; import ca.nrc.cadc.ac.ReaderException; import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.ac.UserDetails; import ca.nrc.cadc.ac.UserRequest; import ca.nrc.cadc.ac.WriterException; -import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.DNPrincipal; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.IdentityType; import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.auth.OpenIdPrincipal; import ca.nrc.cadc.date.DateUtil; - import org.jdom2.Attribute; import org.jdom2.Document; import org.jdom2.Element; @@ -94,20 +92,63 @@ import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; import javax.security.auth.x500.X500Principal; - import java.io.IOException; import java.io.Writer; +import java.lang.reflect.Field; +import java.net.URI; +import java.net.URISyntaxException; import java.security.Principal; import java.text.DateFormat; import java.text.ParseException; import java.util.List; import java.util.Set; +import java.util.UUID; /** * AbstractReaderWriter TODO describe class */ public abstract class AbstractReaderWriter { + public static final String ADDRESS = "address"; + public static final String AUTHORITY = "authority"; + public static final String CITY = "city"; + public static final String COUNTRY = "country"; + public static final String EMAIL = "email"; + public static final String DESCRIPTION = "description"; + public static final String FIRST_NAME = "firstName"; + public static final String GID = "gid"; + public static final String GROUP = "group"; + public static final String GROUPS = "groups"; + public static final String GROUP_ADMINS = "groupAdmins"; + public static final String GROUP_MEMBERS = "groupMembers"; + public static final String HOME_DIRECTORY = "homeDirectory"; + public static final String ID = "id"; + public static final String IDENTITY = "identity"; + public static final String IDENTITIES = "identities"; + public static final String INSTITUTE = "institute"; + public static final String INTEGER = "Integer"; + public static final String INTERNAL_ID = "internalID"; + public static final String KEY = "key"; + public static final String LAST_MODIFIED = "lastModified"; + public static final String LAST_NAME = "lastName"; + public static final String OWNER = "owner"; + public static final String PASSWORD = "password"; + public static final String PERSONAL_DETAILS = "personalDetails"; + public static final String POSIX_DETAILS = "posixDetails"; + public static final String PROPERTIES = "properties"; + public static final String PROPERTY = "property"; + public static final String READ_ONLY = "readOnly"; + public static final String STRING = "String"; + public static final String TYPE = "type"; + public static final String UID = "uid"; + public static final String URI = "uri"; + public static final String USER = "user"; + public static final String USERNAME = "username"; + public static final String USERS = "users"; + public static final String USER_ADMINS = "userAdmins"; + public static final String USER_MEMBERS = "userMembers"; + public static final String USER_REQUEST = "userRequest"; + /** * Write to root Element to a writer. * @@ -130,49 +171,41 @@ public abstract class AbstractReaderWriter * @return A User object. * @throws ReaderException */ - protected final User<Principal> getUser(Element element) + protected final User getUser(Element element) throws ReaderException { - // userID element of the User element - Element userIDElement = element.getChild("userID"); - if (userIDElement == null) - { - String error = "userID element not found in user element"; - throw new ReaderException(error); - } + User user = new User(); - // identity element of the userID element - Element userIDIdentityElement = userIDElement.getChild("identity"); - if (userIDIdentityElement == null) + // id + Element internalIDElement = element.getChild(INTERNAL_ID); + if (internalIDElement != null) { - String error = "identity element not found in userID element"; - throw new ReaderException(error); + setInternalID(user, internalIDElement); } - Principal userID = getPrincipal(userIDIdentityElement); - User<Principal> user = new User<Principal>(userID); - // identities - Element identitiesElement = element.getChild("identities"); + Element identitiesElement = element.getChild(IDENTITIES); if (identitiesElement != null) { - List<Element> identityElements = identitiesElement.getChildren("identity"); + List<Element> identityElements = identitiesElement.getChildren(IDENTITY); for (Element identityElement : identityElements) { user.getIdentities().add(getPrincipal(identityElement)); } + } + // personalDetails + Element personalDetailsElement = element.getChild(PERSONAL_DETAILS); + if (personalDetailsElement != null) + { + user.personalDetails = getPersonalDetails(personalDetailsElement); } - // details - Element detailsElement = element.getChild("details"); - if (detailsElement != null) + // posixDetails + Element posixDetailsElement = element.getChild(POSIX_DETAILS); + if (posixDetailsElement != null) { - List<Element> userDetailsElements = detailsElement.getChildren("userDetails"); - for (Element userDetailsElement : userDetailsElements) - { - user.details.add(getUserDetails(userDetailsElement)); - } + user.posixDetails = getPosixDetails(posixDetailsElement); } return user; @@ -185,20 +218,20 @@ public abstract class AbstractReaderWriter * @return A UserRequest object. * @throws ReaderException */ - protected final UserRequest<Principal> getUserRequest(Element element) + protected final UserRequest getUserRequest(Element element) throws ReaderException { // user element of the UserRequest element - Element userElement = element.getChild("user"); + Element userElement = element.getChild(USER); if (userElement == null) { String error = "user element not found in userRequest element"; throw new ReaderException(error); } - User<Principal> user = getUser(userElement); + User user = getUser(userElement); // password element of the userRequest element - Element passwordElement = element.getChild("password"); + Element passwordElement = element.getChild(PASSWORD); if (passwordElement == null) { String error = "password element not found in userRequest element"; @@ -206,7 +239,7 @@ public abstract class AbstractReaderWriter } String password = passwordElement.getText(); - return new UserRequest<Principal>(user, password.toCharArray()); + return new UserRequest(user, password.toCharArray()); } /** @@ -225,14 +258,14 @@ public abstract class AbstractReaderWriter throw new ReaderException(error); } - if (!element.getName().equals("identity")) + if (!element.getName().equals(IDENTITY)) { String error = "expected identity element name, found " + element.getName(); throw new ReaderException(error); } - String type = element.getAttributeValue("type"); + String type = element.getAttributeValue(TYPE); if (type == null) { String error = "type attribute not found in identity element" + @@ -248,17 +281,7 @@ public abstract class AbstractReaderWriter } else if (type.equals(IdentityType.CADC.getValue())) { - Integer cadcID; - try - { - cadcID = Integer.valueOf(identity); - } - catch (NumberFormatException e) - { - String error = "Non-integer cadcID: " + identity; - throw new ReaderException(error); - } - principal = new NumericPrincipal(cadcID); + principal = new NumericPrincipal(UUID.fromString(identity)); } else if (type.equals(IdentityType.USERNAME.getValue())) { @@ -282,59 +305,32 @@ public abstract class AbstractReaderWriter } /** - * Get a UserDetails object from a JDOM element. + * Get a PosixDetails object from a JDOM element. * - * @param element The UserDetails JDOM element. - * @return A UserDetails object. + * @param element The PosixDetails JDOM element. + * @return A PosixDetails object. * @throws ReaderException */ - protected final UserDetails getUserDetails(Element element) + protected final PosixDetails getPosixDetails(Element element) throws ReaderException { if (element == null) { - throw new ReaderException("null UserDetails"); - } - - if (!element.getName().equals(UserDetails.NAME)) - { - String error = "expected element name userDetails, found " + - element.getName(); + String error = "null posixDetails element"; throw new ReaderException(error); } - String type = element.getAttributeValue(UserDetails.TYPE_ATTRIBUTE); - if (type == null) + // userName + Element userNameElement = element.getChild(USERNAME); + if (userNameElement == null) { - String error = "userDetails missing required attribute type"; + String error = "posixDetails missing required element username"; throw new ReaderException(error); } + String username = userNameElement.getText(); - if (type.equals(PosixDetails.NAME)) - { - return getPosixDetails(element); - } - if (type.equals(PersonalDetails.NAME)) - { - return getPersonalDetails(element); - } - - String error = "Unknown UserDetails attribute type " + type; - throw new ReaderException(error); - } - - /** - * Get a PosixDetails object from a JDOM element. - * - * @param element The PosixDetails JDOM element. - * @return A PosixDetails object. - * @throws ReaderException - */ - protected final PosixDetails getPosixDetails(Element element) - throws ReaderException - { // uid - Element uidElement = element.getChild(PosixDetails.UID); + Element uidElement = element.getChild(UID); if (uidElement == null) { String error = "posixDetails missing required element uid"; @@ -352,7 +348,7 @@ public abstract class AbstractReaderWriter } // gid - Element gidElement = element.getChild(PosixDetails.GID); + Element gidElement = element.getChild(GID); if (gidElement == null) { String error = "posixDetails missing required element gid"; @@ -370,7 +366,7 @@ public abstract class AbstractReaderWriter } // homeDirectory - Element homeDirElement = element.getChild(PosixDetails.HOME_DIRECTORY); + Element homeDirElement = element.getChild(HOME_DIRECTORY); if (homeDirElement == null) { String error = "posixDetails missing required element homeDirectory"; @@ -378,7 +374,7 @@ public abstract class AbstractReaderWriter } String homeDirectory = homeDirElement.getText(); - return new PosixDetails(uid, gid, homeDirectory); + return new PosixDetails(username, uid, gid, homeDirectory); } /** @@ -391,8 +387,14 @@ public abstract class AbstractReaderWriter protected final PersonalDetails getPersonalDetails(Element element) throws ReaderException { + if (element == null) + { + String error = "null personalDetails element"; + throw new ReaderException(error); + } + // firstName - Element firstNameElement = element.getChild(PersonalDetails.FIRSTNAME); + Element firstNameElement = element.getChild(FIRST_NAME); if (firstNameElement == null) { String error = "personalDetails missing required element firstName"; @@ -401,7 +403,7 @@ public abstract class AbstractReaderWriter String firstName = firstNameElement.getText(); // lastName - Element lastNameElement = element.getChild(PersonalDetails.LASTNAME); + Element lastNameElement = element.getChild(LAST_NAME); if (lastNameElement == null) { String error = "personalDetails missing required element lastName"; @@ -412,35 +414,35 @@ public abstract class AbstractReaderWriter PersonalDetails details = new PersonalDetails(firstName, lastName); // email - Element emailElement = element.getChild(PersonalDetails.EMAIL); + Element emailElement = element.getChild(EMAIL); if (emailElement != null) { details.email = emailElement.getText(); } // address - Element addressElement = element.getChild(PersonalDetails.ADDRESS); + Element addressElement = element.getChild(ADDRESS); if (addressElement != null) { details.address = addressElement.getText(); } // institute - Element instituteElement = element.getChild(PersonalDetails.INSTITUTE); + Element instituteElement = element.getChild(INSTITUTE); if (instituteElement != null) { details.institute = instituteElement.getText(); } // city - Element cityElement = element.getChild(PersonalDetails.CITY); + Element cityElement = element.getChild(CITY); if (cityElement != null) { details.city = cityElement.getText(); } // country - Element countryElement = element.getChild(PersonalDetails.COUNTRY); + Element countryElement = element.getChild(COUNTRY); if (countryElement != null) { details.country = countryElement.getText(); @@ -459,7 +461,7 @@ public abstract class AbstractReaderWriter protected final Group getGroup(Element element) throws ReaderException { - String uri = element.getAttributeValue("uri"); + String uri = element.getAttributeValue(URI); if (uri == null) { String error = "group missing required uri attribute"; @@ -476,12 +478,12 @@ public abstract class AbstractReaderWriter String groupID = uri.substring(AC.GROUP_URI.length()); // Group owner - User<? extends Principal> user = null; - Element ownerElement = element.getChild("owner"); + User user = null; + Element ownerElement = element.getChild(OWNER); if (ownerElement != null) { // Owner user - Element userElement = ownerElement.getChild("user"); + Element userElement = ownerElement.getChild(USER); if (userElement == null) { String error = "owner missing required user element"; @@ -490,17 +492,20 @@ public abstract class AbstractReaderWriter user = getUser(userElement); } - Group group = new Group(groupID, user); + Group group = new Group(groupID); + + // set owner field + setField(group, user, OWNER); // description - Element descriptionElement = element.getChild("description"); + Element descriptionElement = element.getChild(DESCRIPTION); if (descriptionElement != null) { group.description = descriptionElement.getText(); } // lastModified - Element lastModifiedElement = element.getChild("lastModified"); + Element lastModifiedElement = element.getChild(LAST_MODIFIED); if (lastModifiedElement != null) { try @@ -517,10 +522,10 @@ public abstract class AbstractReaderWriter } // properties - Element propertiesElement = element.getChild("properties"); + Element propertiesElement = element.getChild(PROPERTIES); if (propertiesElement != null) { - List<Element> propertyElements = propertiesElement.getChildren("property"); + List<Element> propertyElements = propertiesElement.getChildren(PROPERTY); for (Element propertyElement : propertyElements) { group.getProperties().add(getGroupProperty(propertyElement)); @@ -528,10 +533,10 @@ public abstract class AbstractReaderWriter } // groupMembers - Element groupMembersElement = element.getChild("groupMembers"); + Element groupMembersElement = element.getChild(GROUP_MEMBERS); if (groupMembersElement != null) { - List<Element> groupElements = groupMembersElement.getChildren("group"); + List<Element> groupElements = groupMembersElement.getChildren(GROUP); for (Element groupMember : groupElements) { group.getGroupMembers().add(getGroup(groupMember)); @@ -539,10 +544,10 @@ public abstract class AbstractReaderWriter } // userMembers - Element userMembersElement = element.getChild("userMembers"); + Element userMembersElement = element.getChild(USER_MEMBERS); if (userMembersElement != null) { - List<Element> userElements = userMembersElement.getChildren("user"); + List<Element> userElements = userMembersElement.getChildren(USER); for (Element userMember : userElements) { group.getUserMembers().add(getUser(userMember)); @@ -550,10 +555,10 @@ public abstract class AbstractReaderWriter } // groupAdmins - Element groupAdminsElement = element.getChild("groupAdmins"); + Element groupAdminsElement = element.getChild(GROUP_ADMINS); if (groupAdminsElement != null) { - List<Element> groupElements = groupAdminsElement.getChildren("group"); + List<Element> groupElements = groupAdminsElement.getChildren(GROUP); for (Element groupMember : groupElements) { group.getGroupAdmins().add(getGroup(groupMember)); @@ -561,10 +566,10 @@ public abstract class AbstractReaderWriter } // userAdmins - Element userAdminsElement = element.getChild("userAdmins"); + Element userAdminsElement = element.getChild(USER_ADMINS); if (userAdminsElement != null) { - List<Element> userElements = userAdminsElement.getChildren("user"); + List<Element> userElements = userAdminsElement.getChildren(USER); for (Element userMember : userElements) { group.getUserAdmins().add(getUser(userMember)); @@ -590,34 +595,34 @@ public abstract class AbstractReaderWriter throw new ReaderException(error); } - if (!element.getName().equals(GroupProperty.NAME)) + if (!element.getName().equals(PROPERTY)) { String error = "expected property element name, found " + element.getName(); throw new ReaderException(error); } - String key = element.getAttributeValue(GroupProperty.KEY_ATTRIBUTE); + String key = element.getAttributeValue(KEY); if (key == null) { String error = "required key attribute not found"; throw new ReaderException(error); } - String type = element.getAttributeValue(GroupProperty.TYPE_ATTRIBUTE); + String type = element.getAttributeValue(TYPE); if (type == null) { String error = "required type attribute not found"; throw new ReaderException(error); } Object value; - if (type.equals(GroupProperty.STRING_TYPE)) + if (type.equals(STRING)) { value = String.valueOf(element.getText()); } else { - if (type.equals(GroupProperty.INTEGER_TYPE)) + if (type.equals(INTEGER)) { value = Integer.valueOf(element.getText()); } @@ -627,7 +632,7 @@ public abstract class AbstractReaderWriter throw new ReaderException(error); } } - Boolean readOnly = Boolean.valueOf(element.getAttributeValue(GroupProperty.READONLY_ATTRIBUTE)); + Boolean readOnly = Boolean.valueOf(element.getAttributeValue(READ_ONLY)); return new GroupProperty(key, value, readOnly); } @@ -639,42 +644,45 @@ public abstract class AbstractReaderWriter * @return A JDOM User representation. * @throws WriterException */ - protected final Element getElement(User<? extends Principal> user) + protected final Element getElement(User user) throws WriterException { + if (user == null) + { + throw new WriterException("null User"); + } + // Create the user Element. - Element userElement = new Element("user"); + Element userElement = new Element(USER); - // userID element - Element userIDElement = new Element("userID"); - userIDElement.addContent(getElement(user.getUserID())); - userElement.addContent(userIDElement); + // internalID element + if (user.getID() != null) + { + userElement.addContent(getElement(user.getID())); + } // identities Set<Principal> identities = user.getIdentities(); - if (identities.size() > 1) // includes alternate identies + if (!identities.isEmpty()) // includes alternate identities { - Element identitiesElement = new Element("identities"); + Element identitiesElement = new Element(IDENTITIES); for (Principal identity : identities) { - // userID is in this list, so only include alternate identities - // in the output - if (!AuthenticationUtil.equals(identity, user.getUserID())) - identitiesElement.addContent(getElement(identity)); + identitiesElement.addContent(getElement(identity)); } userElement.addContent(identitiesElement); } - // details - if (!user.details.isEmpty()) + // personalDetails + if (user.personalDetails != null) { - Element detailsElement = new Element("details"); - Set<UserDetails> userDetails = user.details; - for (UserDetails userDetail : userDetails) - { - detailsElement.addContent(getElement(userDetail)); - } - userElement.addContent(detailsElement); + userElement.addContent(getElement(user.personalDetails)); + } + + // posixDetails + if (user.posixDetails != null) + { + userElement.addContent(getElement(user.posixDetails)); } return userElement; @@ -687,24 +695,55 @@ public abstract class AbstractReaderWriter * @return A JDOM UserRequest representation. * @throws WriterException */ - protected final Element getElement(UserRequest<? extends Principal> userRequest) + protected final Element getElement(UserRequest userRequest) throws WriterException { + if (userRequest == null) + { + throw new WriterException("null UserRequest"); + } + // Create the userRequest Element. - Element userRequestElement = new Element("userRequest"); + Element userRequestElement = new Element(USER_REQUEST); // user element Element userElement = getElement(userRequest.getUser()); userRequestElement.addContent(userElement); // password element - Element passwordElement = new Element("password"); + Element passwordElement = new Element(PASSWORD); passwordElement.setText(String.valueOf(userRequest.getPassword())); userRequestElement.addContent(passwordElement); return userRequestElement; } + /** + * Get a JDOM element from a InternalID object. + * + * @param internalID The InternalID. + * @return A JDOM InternalID representation. + * @throws WriterException + */ + protected final Element getElement(InternalID internalID) + throws WriterException + { + if (internalID == null) + { + throw new WriterException("null InternalID"); + } + + // Create the internalID Element. + Element internalIDElement = new Element(INTERNAL_ID); + + // uri element + Element uriElement = new Element(URI); + uriElement.addContent(internalID.getURI().toString()); + internalIDElement.addContent(uriElement); + + return internalIDElement; + } + /** * Get a JDOM element from a Principal object. * @@ -717,30 +756,30 @@ public abstract class AbstractReaderWriter { if (identity == null) { - String error = "null identity"; + String error = "null Principal"; throw new WriterException(error); } - Element identityElement = new Element("identity"); + Element identityElement = new Element(IDENTITY); if ((identity instanceof HttpPrincipal)) { - identityElement.setAttribute("type", IdentityType.USERNAME.getValue()); + identityElement.setAttribute(TYPE, IdentityType.USERNAME.getValue()); } else if ((identity instanceof NumericPrincipal)) { - identityElement.setAttribute("type", IdentityType.CADC.getValue()); + identityElement.setAttribute(TYPE, IdentityType.CADC.getValue()); } else if ((identity instanceof OpenIdPrincipal)) { - identityElement.setAttribute("type", IdentityType.OPENID.getValue()); + identityElement.setAttribute(TYPE, IdentityType.OPENID.getValue()); } else if ((identity instanceof X500Principal)) { - identityElement.setAttribute("type", IdentityType.X500.getValue()); + identityElement.setAttribute(TYPE, IdentityType.X500.getValue()); } else if ((identity instanceof DNPrincipal)) { - identityElement.setAttribute("type", IdentityType.ENTRY_DN.getValue()); + identityElement.setAttribute(TYPE, IdentityType.ENTRY_DN.getValue()); } else { @@ -754,55 +793,35 @@ public abstract class AbstractReaderWriter } /** - * Get a JDOM element from a UserDetails object. + * Get a JDOM element from a PosixDetails object. * - * @param details The UserDetails. - * @return A JDOM UserDetails representation. - * @throws WriterException + * @param details The PosixDetails. + * @return A JDOM PosixDetails representation. */ - protected final Element getElement(UserDetails details) + protected final Element getElement(PosixDetails details) throws WriterException { if (details == null) { - throw new WriterException("null UserDetails"); - } - - if ((details instanceof PosixDetails)) - { - return getElement((PosixDetails) details); - } - if ((details instanceof PersonalDetails)) - { - return getElement((PersonalDetails) details); + String error = "null PosixDetails"; + throw new WriterException(error); } - String error = "Unknown UserDetails implementation: " + - details.getClass().getName(); - throw new WriterException(error); - } + Element detailsElement = new Element(POSIX_DETAILS); - /** - * Get a JDOM element from a PosixDetails object. - * - * @param details The PosixDetails. - * @return A JDOM PosixDetails representation. - */ - protected final Element getElement(PosixDetails details) - { - Element detailsElement = new Element(UserDetails.NAME); - detailsElement.setAttribute(UserDetails.TYPE_ATTRIBUTE, - PosixDetails.NAME); + Element usernameElement = new Element(USERNAME); + usernameElement.setText(details.getUsername()); + detailsElement.addContent(usernameElement); - Element uidElement = new Element(PosixDetails.UID); + Element uidElement = new Element(UID); uidElement.setText(String.valueOf(details.getUid())); detailsElement.addContent(uidElement); - Element gidElement = new Element(PosixDetails.GID); + Element gidElement = new Element(GID); gidElement.setText(String.valueOf(details.getGid())); detailsElement.addContent(gidElement); - Element homeDirElement = new Element(PosixDetails.HOME_DIRECTORY); + Element homeDirElement = new Element(HOME_DIRECTORY); homeDirElement.setText(details.getHomeDirectory()); detailsElement.addContent(homeDirElement); @@ -816,50 +835,55 @@ public abstract class AbstractReaderWriter * @return JDOM PersonalDetails representation. */ protected final Element getElement(PersonalDetails details) + throws WriterException { - Element detailsElement = new Element(UserDetails.NAME); - detailsElement.setAttribute(UserDetails.TYPE_ATTRIBUTE, - PersonalDetails.NAME); + if (details == null) + { + String error = "null PersonalDetails"; + throw new WriterException(error); + } + + Element detailsElement = new Element(PERSONAL_DETAILS); - Element firstNameElement = new Element(PersonalDetails.FIRSTNAME); + Element firstNameElement = new Element(FIRST_NAME); firstNameElement.setText(details.getFirstName()); detailsElement.addContent(firstNameElement); - Element lastNameElement = new Element(PersonalDetails.LASTNAME); + Element lastNameElement = new Element(LAST_NAME); lastNameElement.setText(details.getLastName()); detailsElement.addContent(lastNameElement); if (details.email != null) { - Element emailElement = new Element(PersonalDetails.EMAIL); + Element emailElement = new Element(EMAIL); emailElement.setText(details.email); detailsElement.addContent(emailElement); } if (details.address != null) { - Element addressElement = new Element(PersonalDetails.ADDRESS); + Element addressElement = new Element(ADDRESS); addressElement.setText(details.address); detailsElement.addContent(addressElement); } if (details.institute != null) { - Element instituteElement = new Element(PersonalDetails.INSTITUTE); + Element instituteElement = new Element(INSTITUTE); instituteElement.setText(details.institute); detailsElement.addContent(instituteElement); } if (details.city != null) { - Element cityElement = new Element(PersonalDetails.CITY); + Element cityElement = new Element(CITY); cityElement.setText(details.city); detailsElement.addContent(cityElement); } if (details.country != null) { - Element countryElement = new Element(PersonalDetails.COUNTRY); + Element countryElement = new Element(COUNTRY); countryElement.setText(details.country); detailsElement.addContent(countryElement); } @@ -891,15 +915,20 @@ public abstract class AbstractReaderWriter protected final Element getElement(Group group, boolean deepCopy) throws WriterException { + if (group == null) + { + throw new WriterException("null Group"); + } + // Create the root group element. - Element groupElement = new Element("group"); + Element groupElement = new Element(GROUP); String groupURI = AC.GROUP_URI + group.getID(); - groupElement.setAttribute(new Attribute("uri", groupURI)); + groupElement.setAttribute(new Attribute(URI, groupURI)); // Group owner if (group.getOwner() != null) { - Element ownerElement = new Element("owner"); + Element ownerElement = new Element(OWNER); Element userElement = getElement(group.getOwner()); ownerElement.addContent(userElement); groupElement.addContent(ownerElement); @@ -910,7 +939,7 @@ public abstract class AbstractReaderWriter // Group description if (group.description != null) { - Element descriptionElement = new Element("description"); + Element descriptionElement = new Element(DESCRIPTION); descriptionElement.setText(group.description); groupElement.addContent(descriptionElement); } @@ -918,7 +947,7 @@ public abstract class AbstractReaderWriter // lastModified if (group.lastModified != null) { - Element lastModifiedElement = new Element("lastModified"); + Element lastModifiedElement = new Element(LAST_MODIFIED); DateFormat df = DateUtil.getDateFormat(DateUtil.IVOA_DATE_FORMAT, DateUtil.UTC); lastModifiedElement.setText(df.format(group.lastModified)); groupElement.addContent(lastModifiedElement); @@ -927,7 +956,7 @@ public abstract class AbstractReaderWriter // Group properties if (!group.getProperties().isEmpty()) { - Element propertiesElement = new Element("properties"); + Element propertiesElement = new Element(PROPERTIES); for (GroupProperty property : group.getProperties()) { propertiesElement.addContent(getElement(property)); @@ -938,7 +967,7 @@ public abstract class AbstractReaderWriter // Group groupMembers. if ((group.getGroupMembers() != null) && (!group.getGroupMembers().isEmpty())) { - Element groupMembersElement = new Element("groupMembers"); + Element groupMembersElement = new Element(GROUP_MEMBERS); for (Group groupMember : group.getGroupMembers()) { groupMembersElement.addContent(getElement(groupMember, false)); @@ -949,8 +978,8 @@ public abstract class AbstractReaderWriter // Group userMembers if ((group.getUserMembers() != null) && (!group.getUserMembers().isEmpty())) { - Element userMembersElement = new Element("userMembers"); - for (User<? extends Principal> userMember : group.getUserMembers()) + Element userMembersElement = new Element(USER_MEMBERS); + for (User userMember : group.getUserMembers()) { userMembersElement.addContent(getElement(userMember)); } @@ -960,7 +989,7 @@ public abstract class AbstractReaderWriter // Group groupAdmins. if ((group.getGroupAdmins() != null) && (!group.getGroupAdmins().isEmpty())) { - Element groupAdminsElement = new Element("groupAdmins"); + Element groupAdminsElement = new Element(GROUP_ADMINS); for (Group groupMember : group.getGroupAdmins()) { groupAdminsElement.addContent(getElement(groupMember, false)); @@ -971,8 +1000,8 @@ public abstract class AbstractReaderWriter // Group userAdmins if ((group.getUserAdmins() != null) && (!group.getUserAdmins().isEmpty())) { - Element userAdminsElement = new Element("userAdmins"); - for (User<? extends Principal> userMember : group.getUserAdmins()) + Element userAdminsElement = new Element(USER_ADMINS); + for (User userMember : group.getUserAdmins()) { userAdminsElement.addContent(getElement(userMember)); } @@ -998,25 +1027,21 @@ public abstract class AbstractReaderWriter throw new WriterException("null GroupProperty"); } - Element propertyElement = new Element(GroupProperty.NAME); - propertyElement.setAttribute(GroupProperty.KEY_ATTRIBUTE, - property.getKey()); + Element propertyElement = new Element(PROPERTY); + propertyElement.setAttribute(KEY, property.getKey()); if (property.isReadOnly()) { - propertyElement.setAttribute(GroupProperty.READONLY_ATTRIBUTE, - "true"); + propertyElement.setAttribute(READ_ONLY, Boolean.TRUE.toString()); } Object value = property.getValue(); if ((value instanceof String)) { - propertyElement.setAttribute(GroupProperty.TYPE_ATTRIBUTE, - GroupProperty.STRING_TYPE); + propertyElement.setAttribute(TYPE, STRING); } else if ((value instanceof Integer)) { - propertyElement.setAttribute(GroupProperty.TYPE_ATTRIBUTE, - GroupProperty.INTEGER_TYPE); + propertyElement.setAttribute(TYPE, INTEGER); } else { @@ -1029,4 +1054,51 @@ public abstract class AbstractReaderWriter return propertyElement; } + private void setInternalID(User user, Element element) + throws ReaderException + { + Element uriElement = element.getChild(URI); + if (uriElement == null) + { + String error = "expected uri element not found in internalID element"; + throw new ReaderException(error); + } + String text = uriElement.getText(); + URI uri; + try + { + uri = new URI(text); + } + catch (URISyntaxException e) + { + throw new ReaderException("Invalid InternalID URI " + text, e); + } + + InternalID internalID = new InternalID(uri); + setField(user, internalID, ID); + } + + // set private field using reflection + private void setField(Object object, Object value, String name) + { + try + { + Field field = object.getClass().getDeclaredField(name); + field.setAccessible(true); + field.set(object, value); + } + catch (NoSuchFieldException e) + { + final String error = object.getClass().getSimpleName() + + " field " + name + "not found"; + throw new RuntimeException(error, e); + } + catch (IllegalAccessException e) + { + final String error = "unable to update " + name + " in " + + object.getClass().getSimpleName(); + throw new RuntimeException(error, e); + } + } + } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupListReader.java b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupListReader.java index da9f16c848b0c53e57051d62d4a241012b1392db..1b2aa68b0dd20bf8b22881067b2605c3c3658ba7 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupListReader.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupListReader.java @@ -170,7 +170,7 @@ public class GroupListReader extends AbstractReaderWriter String groupElemName = root.getName(); - if (!groupElemName.equalsIgnoreCase("groups")) + if (!groupElemName.equalsIgnoreCase(GROUPS)) { String error = "Expected groups element, found " + groupElemName; throw new ReaderException(error); @@ -192,7 +192,7 @@ public class GroupListReader extends AbstractReaderWriter {; List<Group> groups = new ArrayList<Group>(); - List<Element> groupElements = element.getChildren("group"); + List<Element> groupElements = element.getChildren(GROUP); for (Element groupElement : groupElements) { groups.add(getGroup(groupElement)); diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupListWriter.java b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupListWriter.java index a42cff8bef88bf2965dd59888ea8cd81e8838abb..94585a081f44fd708c18088c371d61472132e5b7 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupListWriter.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupListWriter.java @@ -152,7 +152,7 @@ public class GroupListWriter extends AbstractReaderWriter protected final Element getElement(Collection<Group> groups) throws WriterException { - Element groupsElement = new Element("groups"); + Element groupsElement = new Element(GROUPS); for (Group group : groups) { diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupReader.java b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupReader.java index b9c64d1bcd3a75ed9855739db1df0f999fe0fe7d..44fc31fff9ee973c0e17ac6093d93ee19dbf820d 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupReader.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupReader.java @@ -168,7 +168,7 @@ public class GroupReader extends AbstractReaderWriter String groupElemName = root.getName(); - if (!groupElemName.equalsIgnoreCase("group")) + if (!groupElemName.equalsIgnoreCase(GROUP)) { String error = "Expected group element, found " + groupElemName; throw new ReaderException(error); diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserListReader.java b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserListReader.java index 9726a22966b3533e275c702182d3218d17e19105..d78e94d67ee9c6e78f9e7d62c437f45e66019fda 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserListReader.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserListReader.java @@ -82,7 +82,6 @@ import java.io.Reader; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; -import java.security.Principal; import java.util.ArrayList; import java.util.List; @@ -101,7 +100,7 @@ public class UserListReader extends AbstractReaderWriter * @throws java.io.IOException * @throws java.net.URISyntaxException */ - public List<User<Principal>> read(String xml) + public List<User> read(String xml) throws ReaderException, IOException, URISyntaxException { if (xml == null) @@ -120,7 +119,7 @@ public class UserListReader extends AbstractReaderWriter * @throws java.io.IOException * @throws java.net.URISyntaxException */ - public List<User<Principal>> read(InputStream in) + public List<User> read(InputStream in) throws ReaderException, IOException { if (in == null) @@ -147,7 +146,7 @@ public class UserListReader extends AbstractReaderWriter * @throws ReaderException * @throws java.io.IOException */ - public List<User<Principal>> read(Reader reader) + public List<User> read(Reader reader) throws ReaderException, IOException { if (reader == null) @@ -170,7 +169,7 @@ public class UserListReader extends AbstractReaderWriter String userElemName = root.getName(); - if (!userElemName.equalsIgnoreCase("users")) + if (!userElemName.equalsIgnoreCase(USERS)) { String error = "Expected users element, found " + userElemName; throw new ReaderException(error); @@ -186,12 +185,12 @@ public class UserListReader extends AbstractReaderWriter * @return A List of User objects. * @throws ReaderException */ - protected final List<User<Principal>> getUserList(Element element) + protected final List<User> getUserList(Element element) throws ReaderException { - List<User<Principal>> users = new ArrayList<User<Principal>>(); + List<User> users = new ArrayList<User>(); - List<Element> userElements = element.getChildren("user"); + List<Element> userElements = element.getChildren(USER); for (Element userElement : userElements) { users.add(getUser(userElement)); diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserListWriter.java b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserListWriter.java index a9d25c8d3b7957f9360d339d13354833dd95f588..1a74d77140b49a151861bd2dc8319570a82239fd 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserListWriter.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserListWriter.java @@ -95,7 +95,7 @@ public class UserListWriter extends AbstractReaderWriter * @throws java.io.IOException * @throws WriterException */ - public <T extends Principal> void write(Collection<User<T>> users, StringBuilder builder) + public <T extends Principal> void write(Collection<User> users, StringBuilder builder) throws IOException, WriterException { write(users, new StringBuilderWriter(builder)); @@ -109,7 +109,7 @@ public class UserListWriter extends AbstractReaderWriter * @throws IOException if the writer fails to write. * @throws WriterException */ - public <T extends Principal> void write(Collection<User<T>> users, OutputStream out) + public <T extends Principal> void write(Collection<User> users, OutputStream out) throws IOException, WriterException { OutputStreamWriter outWriter; @@ -132,7 +132,7 @@ public class UserListWriter extends AbstractReaderWriter * @throws IOException if the writer fails to write. * @throws WriterException */ - public <T extends Principal> void write(Collection<User<T>> users, Writer writer) + public <T extends Principal> void write(Collection<User> users, Writer writer) throws IOException, WriterException { if (users == null) @@ -152,11 +152,11 @@ public class UserListWriter extends AbstractReaderWriter * @throws WriterException */ protected final <T extends Principal> Element getElement( - Collection<User<T>> users) throws WriterException + Collection<User> users) throws WriterException { Element usersElement = new Element("users"); - for (User<T> user : users) + for (User user : users) { usersElement.addContent(getElement(user)); } diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserReader.java b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserReader.java index c3cbae20aaa3f64e875560f521b1776366f98aca..690d650e6f2ff7b99b3852b7ffdf258f41cd358d 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserReader.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserReader.java @@ -82,7 +82,6 @@ import java.io.Reader; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; -import java.security.Principal; /** * Class to read a XML representation of a User to a User object. @@ -98,8 +97,8 @@ public class UserReader extends AbstractReaderWriter * @throws java.io.IOException * @throws java.net.URISyntaxException */ - public User<Principal> read(String xml) - throws IOException, URISyntaxException + public User read(String xml) + throws ReaderException, IOException, URISyntaxException { if (xml == null) { @@ -115,8 +114,8 @@ public class UserReader extends AbstractReaderWriter * @return User User. * @throws java.io.IOException */ - public User<Principal> read(InputStream in) - throws IOException + public User read(InputStream in) + throws ReaderException, IOException { if (in == null) { @@ -142,8 +141,8 @@ public class UserReader extends AbstractReaderWriter * @throws ReaderException * @throws java.io.IOException */ - public User<Principal> read(Reader reader) - throws IOException + public User read(Reader reader) + throws ReaderException, IOException { if (reader == null) { diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestReader.java b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestReader.java index dffef3e5e7f65d9fc3217f18f19f3a641189a095..2c147ed0bbfac20de7c233a71b2d349b11f98565 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestReader.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestReader.java @@ -95,8 +95,8 @@ public class UserRequestReader extends AbstractReaderWriter * @return UserRequest UserRequest. * @throws java.io.IOException */ - public UserRequest<Principal> read(String xml) - throws IOException + public UserRequest read(String xml) + throws ReaderException, IOException { if (xml == null) { @@ -113,8 +113,8 @@ public class UserRequestReader extends AbstractReaderWriter * @throws ReaderException * @throws java.io.IOException */ - public UserRequest<Principal> read(InputStream in) - throws IOException + public UserRequest read(InputStream in) + throws ReaderException, IOException { if (in == null) { @@ -140,8 +140,8 @@ public class UserRequestReader extends AbstractReaderWriter * @throws ReaderException * @throws java.io.IOException */ - public UserRequest<Principal> read(Reader reader) - throws IOException + public UserRequest read(Reader reader) + throws ReaderException, IOException { if (reader == null) { diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestWriter.java b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestWriter.java index e87840d129da63713cd78b9b5107413dec04404e..bd16263c23a4b2a08de498dacb310d7d1cb2107d 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestWriter.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestWriter.java @@ -75,7 +75,6 @@ import ca.nrc.cadc.util.StringBuilderWriter; import java.io.IOException; import java.io.Writer; -import java.security.Principal; /** * Class to write a XML representation of a UserRequest object. @@ -90,7 +89,7 @@ public class UserRequestWriter extends AbstractReaderWriter * @throws java.io.IOException if the writer fails to write. * @throws WriterException */ - public <T extends Principal> void write(UserRequest<T> userRequest, StringBuilder builder) + public void write(UserRequest userRequest, StringBuilder builder) throws IOException, WriterException { write(userRequest, new StringBuilderWriter(builder)); @@ -104,7 +103,7 @@ public class UserRequestWriter extends AbstractReaderWriter * @throws IOException if the writer fails to write. * @throws WriterException */ - public <T extends Principal> void write(UserRequest<T> userRequest, Writer writer) + public void write(UserRequest userRequest, Writer writer) throws IOException, WriterException { if (userRequest == null) diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserWriter.java b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserWriter.java index 7df99cbb6e0d284eb1c8f5df5fde0995f5398fc2..729b63ce789719e5c5d68039f9d5d8a1b4c03760 100755 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserWriter.java +++ b/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserWriter.java @@ -78,7 +78,6 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; -import java.security.Principal; /** * Class to write a XML representation of a User object. @@ -93,7 +92,7 @@ public class UserWriter extends AbstractReaderWriter * @throws java.io.IOException if the writer fails to write. * @throws WriterException */ - public <T extends Principal> void write(User<T> user, StringBuilder builder) + public void write(User user, StringBuilder builder) throws IOException, WriterException { write(user, new StringBuilderWriter(builder)); @@ -107,7 +106,7 @@ public class UserWriter extends AbstractReaderWriter * @throws IOException if the writer fails to write. * @throws WriterException */ - public <T extends Principal> void write(User<T> user, OutputStream out) + public void write(User user, OutputStream out) throws IOException, WriterException { OutputStreamWriter outWriter; @@ -130,7 +129,7 @@ public class UserWriter extends AbstractReaderWriter * @throws IOException if the writer fails to write. * @throws WriterException */ - public <T extends Principal> void write(User<T> user, Writer writer) + public void write(User user, Writer writer) throws IOException, WriterException { if (user == null) diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupPropertyTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupPropertyTest.java index b19171c414d64d3d812cc3c55e3ac6bf4709e2be..ebcd65fcbdafdeed32fbe27a5ec0d73cbe01b4ae 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupPropertyTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupPropertyTest.java @@ -92,7 +92,6 @@ public class GroupPropertyTest GroupProperty gp2 = gp1; assertEquals(gp1.hashCode(), gp2.hashCode()); assertEquals(gp1, gp2); - assertTrue(gp1 == gp2); // test toString System.out.println(gp1); diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupTest.java index 6451d53418baf3c5fa1099b97b738c508f27b70b..3d92e7676662272af55c3ceddbdd826f49684703 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupTest.java @@ -71,7 +71,6 @@ package ca.nrc.cadc.ac; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import org.apache.log4j.Logger; import org.junit.Test; @@ -81,7 +80,7 @@ import ca.nrc.cadc.auth.HttpPrincipal; public class GroupTest { private static Logger log = Logger.getLogger(GroupTest.class); - + @Test public void simpleGroupTest() throws Exception { @@ -89,106 +88,91 @@ public class GroupTest Group group2 = group1; assertEquals(group1.hashCode(), group2.hashCode()); assertEquals(group1, group2); - assertTrue(group1 == group2); - - User<HttpPrincipal> owner = new User<HttpPrincipal>(new HttpPrincipal("owner")); - Group group3 = new Group("TestGroup", owner); - User<HttpPrincipal> user = new User<HttpPrincipal>(new HttpPrincipal("user")); - + + Group group3 = new Group("TestGroup"); + User user = new User(); + user.getIdentities().add(new HttpPrincipal("foo")); + group3.getUserMembers().add(user); assertEquals(1, group3.getUserMembers().size()); Group group4 = group3; assertEquals(group3.hashCode(), group4.hashCode()); assertEquals(group3, group4); - assertTrue(group3 == group4); - - group4 = new Group("TestGroup", owner); + + group4 = new Group("TestGroup"); assertEquals(group3.hashCode(), group4.hashCode()); assertEquals(group3,group4); - + group4.getUserMembers().add(user); assertEquals(group3.hashCode(), group4.hashCode()); assertEquals(group3,group4); - + group3.getGroupMembers().add(group4); assertEquals(group3.hashCode(), group4.hashCode()); assertEquals(group3,group4); - + group4.getUserAdmins().add(user); assertEquals(group3.hashCode(), group4.hashCode()); assertEquals(group3,group4); - + group3.getGroupAdmins().add(group4); assertEquals(group3.hashCode(), group4.hashCode()); assertEquals(group3,group4); - + group3.description = "Test group"; assertEquals(group3.hashCode(), group4.hashCode()); assertEquals(group3,group4); - - group4 = new Group("NewTestGroup-._~.", owner); + + group4 = new Group("NewTestGroup-._~."); assertFalse(group3.hashCode() == group4.hashCode()); assertFalse(group3.equals(group4)); - + // test toString System.out.println(group3); } - + @Test public void exceptionTests() { boolean thrown = false; try { - new Group(null, new User<HttpPrincipal>(new HttpPrincipal("owner"))); + new Group(null); } catch(IllegalArgumentException e) { thrown = true; } assertTrue(thrown); - - - thrown = false; - try - { - new Group("NewTestGroup", null); - thrown = true; - } - catch(IllegalArgumentException e) - { - fail("Owner can be null"); - } - assertTrue(thrown); - + // invavlid group IDs thrown = false; try { - new Group("New/Test/Group", new User<HttpPrincipal>(new HttpPrincipal("owner"))); + new Group("New/Test/Group"); } catch(IllegalArgumentException e) { thrown = true; } assertTrue(thrown); - + thrown = false; try { - new Group("New%Test%Group", new User<HttpPrincipal>(new HttpPrincipal("owner"))); + new Group("New%Test%Group"); } catch(IllegalArgumentException e) { thrown = true; } assertTrue(thrown); - + thrown = false; try { - new Group("New\\Test\\Group", new User<HttpPrincipal>(new HttpPrincipal("owner"))); + new Group("New\\Test\\Group"); } catch(IllegalArgumentException e) { @@ -196,5 +180,5 @@ public class GroupTest } assertTrue(thrown); } - + } diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/PosixDetailsTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/PosixDetailsTest.java index ba5ecc6a1918edfc8f64d683b6a721e61fd1241b..0d3d277c055faf5d4f32bb4bb19728a04c9955d0 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/PosixDetailsTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/PosixDetailsTest.java @@ -83,8 +83,9 @@ public class PosixDetailsTest @Test public void simplePosixDetailsTest() throws Exception { - PosixDetails pd1 = new PosixDetails(1l, 2l, "/dev/null"); - + PosixDetails pd1 = new PosixDetails("username", 1l, 2l, "/dev/null"); + + assertEquals("username", pd1.getUsername()); assertEquals(1l, pd1.getUid()); assertEquals(2l, pd1.getGid()); assertEquals("/dev/null", pd1.getHomeDirectory()); @@ -104,7 +105,37 @@ public class PosixDetailsTest boolean thrown = false; try { - new PosixDetails(1l, 2l, null); + new PosixDetails(null, 1l, 2l, "/dev/null"); + } + catch(IllegalArgumentException e) + { + thrown = true; + } + assertTrue(thrown); + + try + { + new PosixDetails("", 1l, 2l, "/dev/null"); + } + catch(IllegalArgumentException e) + { + thrown = true; + } + assertTrue(thrown); + + try + { + new PosixDetails("username", 1l, 2l, null); + } + catch(IllegalArgumentException e) + { + thrown = true; + } + assertTrue(thrown); + + try + { + new PosixDetails(null, 1l, 2l, ""); } catch(IllegalArgumentException e) { diff --git a/cadcAccessControl/src/ca/nrc/cadc/ac/UserDetails.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/TestUtil.java similarity index 86% rename from cadcAccessControl/src/ca/nrc/cadc/ac/UserDetails.java rename to cadcAccessControl/test/src/ca/nrc/cadc/ac/TestUtil.java index 92c259f181c9108f7ba6d56a5772022e112e7eee..2df4d8ee9a1b92cb0e123aebb27f67472ce1370e 100644 --- a/cadcAccessControl/src/ca/nrc/cadc/ac/UserDetails.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/TestUtil.java @@ -66,34 +66,19 @@ * ************************************************************************ */ -package ca.nrc.cadc.ac; -public abstract interface UserDetails -{ - /** - * Name of the UserDetails element. - */ - public static final String NAME = "userDetails"; - - /** - * Name of the property type attribute in the UserDetails element. - */ - public static final String TYPE_ATTRIBUTE = "type"; - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - public abstract int hashCode(); +package ca.nrc.cadc.ac; - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - public abstract boolean equals(Object paramObject); +import java.lang.reflect.Field; - public abstract String toString(); +public class TestUtil +{ + public static void setField(Object object, Object value, String name) + throws Exception + { + Field field = object.getClass().getDeclaredField(name); + field.setAccessible(true); + field.set(object, value); + } } diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserRequestTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserRequestTest.java index 7bc85ed92c3c65e1ddd07c0b4c543ea4e6790a02..2847903a76f6c3292c96c76a710c0d5328964c3b 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserRequestTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserRequestTest.java @@ -83,10 +83,10 @@ public class UserRequestTest @Test public void simpleEqualityTests() throws Exception { - UserRequest<HttpPrincipal> ur1 = - new UserRequest<HttpPrincipal>( - new User<HttpPrincipal>(new HttpPrincipal(("foo"))), "password".toCharArray()); - UserRequest<HttpPrincipal> ur2 = ur1; + User user = new User(); + user.getIdentities().add(new HttpPrincipal("foo")); + UserRequest ur1 = new UserRequest(user, "password".toCharArray()); + UserRequest ur2 = ur1; assertEquals(ur1, ur2); assertEquals(ur1.getUser(), ur2.getUser()); assertEquals(ur1.getPassword(), ur2.getPassword()); diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserTest.java index 4f9743d13a4634bbc91a4e6c1fd08da110126e25..488971336ef610d62eb4a6fee47aea9d30194cc3 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserTest.java @@ -69,150 +69,192 @@ package ca.nrc.cadc.ac; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.UUID; import javax.security.auth.x500.X500Principal; import org.apache.log4j.Logger; import org.junit.Test; +import ca.nrc.cadc.auth.DNPrincipal; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; -import ca.nrc.cadc.auth.OpenIdPrincipal; public class UserTest { private static Logger log = Logger.getLogger(UserTest.class); @Test - public void simpleEqualityTests() throws Exception + public void isConsistentTest() throws Exception { + User user1 = new User(); + User user2 = null; - User<HttpPrincipal> user1 = new User<HttpPrincipal>( - new HttpPrincipal("user1")); - User<HttpPrincipal> user2 = user1; - assertEquals(user1, user2); - assertEquals(user1.hashCode(), user2.hashCode()); + assertFalse(user1.isConsistent(user2)); - user2 = new User<HttpPrincipal>(new HttpPrincipal("user1")); - assertEquals(user1, user2); - assertEquals(user1.hashCode(), user2.hashCode()); + user2 = new User(); + //assertTrue(user1.isConsistent(user2)); - user1.details.add(new PersonalDetails("Joe", "Raymond")); - assertEquals(user1, user2); - assertEquals(user1.hashCode(), user2.hashCode()); + HttpPrincipal httpPrincipal = new HttpPrincipal("foo"); + user1.getIdentities().add(httpPrincipal); + assertFalse(user1.isConsistent(user2)); + assertFalse(user2.isConsistent(user1)); + user2.getIdentities().add(httpPrincipal); + assertTrue(user1.isConsistent(user2)); + assertTrue(user2.isConsistent(user1)); - User<X500Principal> user3 = new User<X500Principal>( - new X500Principal("cn=aaa,ou=ca")); - User<HttpPrincipal> user4 = new User<HttpPrincipal>( - new HttpPrincipal("cn=aaa,ou=ca")); - assertFalse(user3.equals(user4)); - assertFalse(user3.hashCode() == user4.hashCode()); + X500Principal x500Principal1 = new X500Principal("cn=foo,c=bar"); + X500Principal x500Principal2 = new X500Principal("cn=bar,c=foo"); - user1.getIdentities().add(new X500Principal("cn=aaa,ou=ca")); - assertEquals(user1, user2); - assertEquals(user1.hashCode(), user2.hashCode()); + user1.getIdentities().add(x500Principal1); + assertFalse(user1.isConsistent(user2)); + assertTrue(user2.isConsistent(user1)); - user1.details.add(new PosixDetails(12, 23, - "/home/myhome")); - assertEquals(user1, user2); - assertEquals(user1.hashCode(), user2.hashCode()); - - User<NumericPrincipal> user5 = new User<NumericPrincipal>( - new NumericPrincipal(32)); - assertFalse(user1.equals(user5)); - - // visual test of toString - System.out.println(user1); - System.out.println(new PersonalDetails("Joe", "Raymond")); - System.out.println(new PosixDetails(12, 23,"/home/myhome")); - + user2.getIdentities().add(x500Principal2); + assertFalse(user1.isConsistent(user2)); + assertFalse(user2.isConsistent(user1)); + + user2.getIdentities().add(x500Principal1); + assertTrue(user1.isConsistent(user2)); + assertFalse(user2.isConsistent(user1)); + + user1.getIdentities().add(x500Principal2); + assertTrue(user1.isConsistent(user2)); + assertTrue(user2.isConsistent(user1)); } - + @Test - public void exceptionTests() + public void simpleEqualityTests() throws Exception { - boolean thrown = false; - try - { - new User<NumericPrincipal>(null); - } - catch(IllegalArgumentException e) - { - thrown = true; - } - assertTrue(thrown); - - thrown = false; - try - { - new PersonalDetails(null, "Raymond"); - } - catch(IllegalArgumentException e) - { - thrown = true; - } - assertTrue(thrown); - - thrown = false; - try - { - new PersonalDetails("Joe", null); - } - catch(IllegalArgumentException e) - { - thrown = true; - } - assertTrue(thrown); - - - thrown = false; - try - { - new PosixDetails(11, 22, null); - } - catch(IllegalArgumentException e) - { - thrown = true; - } - assertTrue(thrown); - - thrown = false; - try - { - new HttpPrincipal(null); - } - catch(IllegalArgumentException e) - { - thrown = true; - } - assertTrue(thrown); - - thrown = false; - try - { - new OpenIdPrincipal(null); - } - catch(IllegalArgumentException e) - { - thrown = true; - } - assertTrue(thrown); + User user1 = new User(); + User user2 = new User(); + + //assertEquals(user1, user2); + //assertEquals(user1.hashCode(), user2.hashCode()); + + // set InternalID +// URI uri1 = new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID()); +// InternalID internalID1 = new InternalID(uri1); +// TestUtil.setField(user1, internalID1, AbstractReaderWriter.ID); +// +// URI uri2 = new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID()); +// InternalID internalID2 = new InternalID(uri2); +// TestUtil.setField(user2, internalID2, AbstractReaderWriter.ID); +// assertFalse(user1.equals(user2)); +// assertFalse(user1.hashCode() == user2.hashCode()); + + user1 = new User(); + user2 = new User(); + + HttpPrincipal httpPrincipal1 = new HttpPrincipal("foo"); + user1.getIdentities().add(httpPrincipal1); + assertFalse(user1.equals(user2)); + //assertFalse(user1.hashCode() == user2.hashCode()); + + user2.getIdentities().add(httpPrincipal1); + assertTrue(user1.equals(user2)); + //assertEquals(user1.hashCode(), user2.hashCode()); + + HttpPrincipal httpPrincipal2 = new HttpPrincipal("bar"); + assertFalse(user1.getIdentities().add(httpPrincipal2)); + assertTrue(user1.equals(user2)); + //assertEquals(user1.hashCode(), user2.hashCode()); + +// X500Principal x500Principal1 = new X500Principal("cn=foo,c=bar"); +// X500Principal x500Principal2 = new X500Principal("cn=bart,c=foo"); +// +// user1.getIdentities().add(x500Principal1); +// assertFalse(user1.equals(user2)); +// //assertFalse(user1.hashCode() == user2.hashCode()); +// +// user2.getIdentities().add(x500Principal1); +// assertTrue(user1.equals(user2)); +// //assertEquals(user1.hashCode(), user2.hashCode()); +// +// user1.getIdentities().add(x500Principal2); +// assertFalse(user1.equals(user2)); +// //assertFalse(user1.hashCode() == user2.hashCode()); +// +// user2.getIdentities().add(x500Principal2); +// assertTrue(user1.equals(user2)); +// //assertEquals(user1.hashCode(), user2.hashCode()); +// +// assertEquals(user1, user2); +// //assertEquals(user1.hashCode(), user2.hashCode()); + + user1.personalDetails = new PersonalDetails("Joe", "Raymond"); + assertEquals(user1, user2); + //assertEquals(user1.hashCode(), user2.hashCode()); + + user1.posixDetails = new PosixDetails("jray", 12, 23, "/home/jray"); + assertEquals(user1, user2); + //assertEquals(user1.hashCode(), user2.hashCode()); } @Test - public void getDetails() throws Exception + public void comparatorTest() throws Exception { - final User<HttpPrincipal> testSubject = - new User<HttpPrincipal>(new HttpPrincipal("test")); + User user = new User(); + boolean result = false; + + // HttpPrincipal + HttpPrincipal httpPrincipal1 = new HttpPrincipal("foo"); + HttpPrincipal httpPrincipal2 = new HttpPrincipal("bar"); + + result = user.getIdentities().add(httpPrincipal1); + assertTrue(result); + result = user.getIdentities().add(httpPrincipal1); + assertFalse(result); - testSubject.details.add(new PersonalDetails("First", "Last")); + result = user.getIdentities().add(httpPrincipal2); + assertFalse(result); - assertTrue("Should be empty.", - testSubject.getDetails(PosixDetails.class).isEmpty()); + // X500Principal + X500Principal x500Principal1 = new X500Principal("cn=foo,c=bar"); + X500Principal x500Principal2 = new X500Principal("cn=bar,c=foo"); - assertEquals("Should be 1.", 1, - testSubject.getDetails(PersonalDetails.class).size()); + result = user.getIdentities().add(x500Principal1); + assertTrue(result); + result = user.getIdentities().add(x500Principal1); + assertFalse(result); + + result = user.getIdentities().add(x500Principal2); + assertTrue(result); + result = user.getIdentities().add(x500Principal2); + assertFalse(result); + + // NumericPrincipal + NumericPrincipal numericPrincipal1 = new NumericPrincipal(UUID.randomUUID()); + NumericPrincipal numericPrincipal2 = new NumericPrincipal(UUID.randomUUID()); + + result = user.getIdentities().add(numericPrincipal1); + assertTrue(result); + result = user.getIdentities().add(numericPrincipal1); + assertFalse(result); + + result = user.getIdentities().add(numericPrincipal2); + assertTrue(result); + result = user.getIdentities().add(numericPrincipal2); + assertFalse(result); + + // DNPrincipal + DNPrincipal dnPrincipal1 = new DNPrincipal("cn=foo,dc=bar"); + DNPrincipal dnPrincipal2 = new DNPrincipal("cn=bar,dc=foo"); + + result = user.getIdentities().add(dnPrincipal1); + assertTrue(result); + result = user.getIdentities().add(dnPrincipal1); + assertFalse(result); + + result = user.getIdentities().add(dnPrincipal2); + assertTrue(result); + result = user.getIdentities().add(dnPrincipal2); + assertFalse(result); } + } diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/GMSClientTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/GMSClientTest.java index 04e7a27ec7a973f830f76d09fe6c79dcb834ebba..c38e2240a0e49ef912a14ccccb285dd6a27f6201 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/GMSClientTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/GMSClientTest.java @@ -69,19 +69,21 @@ package ca.nrc.cadc.ac.client; -import java.io.IOException; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; + import java.net.URI; import java.net.URL; -import java.security.Principal; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.List; import javax.security.auth.Subject; -import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.net.HttpDownload; import org.apache.log4j.Level; +import org.junit.Assert; +import org.junit.Test; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.Role; @@ -89,11 +91,6 @@ import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.reg.client.RegistryClient; import ca.nrc.cadc.util.Log4jInit; -import org.junit.Assert; -import org.junit.Test; - -import static org.easymock.EasyMock.*; - public class GMSClientTest { @@ -102,43 +99,6 @@ public class GMSClientTest Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); } - @Test - public void testGetDisplayUsers() throws Exception - { - final HttpDownload mockHTTPDownload = createMock(HttpDownload.class); - final RegistryClient mockRegistryClient = - createMock(RegistryClient.class); - final URI serviceURI = URI.create("http://mysite.com/users"); - - mockHTTPDownload.setRequestProperty("Accept", "application/json"); - expectLastCall().once(); - - mockHTTPDownload.run(); - expectLastCall().once(); - - expect(mockHTTPDownload.getThrowable()).andReturn(null).once(); - expect(mockHTTPDownload.getContentLength()).andReturn(88l).once(); - expect(mockHTTPDownload.getContentType()).andReturn( - "application/json").once(); - - expect(mockRegistryClient.getServiceURL(serviceURI, "https")).andReturn( - new URL("http://mysite.com/users/endpoint")); - - replay(mockHTTPDownload, mockRegistryClient); - final GMSClient testSubject = - new GMSClient(serviceURI, mockRegistryClient) - { - @Override - HttpDownload createDisplayUsersHTTPDownload( - List<User<? extends Principal>> webUsers) throws IOException - { - return mockHTTPDownload; - } - }; - - testSubject.getDisplayUsers(); - verify(mockHTTPDownload, mockRegistryClient); - } @Test @@ -172,7 +132,6 @@ public class GMSClientTest Assert.assertTrue(client.userIsSubject(userID, subject)); Assert.assertFalse(client.userIsSubject(userID2, subject)); Assert.assertTrue(client.userIsSubject(userID3, subject)); - verify(mockRegistryClient); } @Test @@ -191,7 +150,7 @@ public class GMSClientTest replay(mockRegistryClient); final GMSClient client = new GMSClient(serviceURI, mockRegistryClient); - verify(mockRegistryClient); + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { @@ -243,6 +202,7 @@ public class GMSClientTest } }); + subject = new Subject(); final HttpPrincipal test2UserID = new HttpPrincipal("test2"); subject.getPrincipals().add(test2UserID); diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapperTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapperTest.java index 64501b8cc4aa8052304ca78105a850bb145780dd..ce4caa3360b90e476ddbf3ff6e984fc96c5e2e39 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapperTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/JsonUserListInputStreamWrapperTest.java @@ -68,9 +68,12 @@ package ca.nrc.cadc.ac.client; +import ca.nrc.cadc.ac.InternalID; import ca.nrc.cadc.ac.PersonalDetails; +import ca.nrc.cadc.ac.TestUtil; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.json.JsonUserListWriter; +import ca.nrc.cadc.ac.xml.AbstractReaderWriter; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.util.Log4jInit; @@ -78,10 +81,13 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.StringWriter; import java.io.Writer; +import java.net.URI; import java.security.Principal; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.UUID; + import org.apache.log4j.Level; import org.apache.log4j.Logger; @@ -102,22 +108,24 @@ public class JsonUserListInputStreamWrapperTest @Test public void readInputStream() throws Exception { - final List<User<? extends Principal>> output = - new ArrayList<User<? extends Principal>>(); + final List<User> output = new ArrayList<User>(); final JsonUserListInputStreamWrapper testSubject = new JsonUserListInputStreamWrapper(output); final JsonUserListWriter userListWriter = new JsonUserListWriter(); final Writer writer = new StringWriter(); - final Collection<User<HttpPrincipal>> users = - new ArrayList<User<HttpPrincipal>>(); - - users.add(new User<HttpPrincipal>(new HttpPrincipal("CADCTest"))); - - final User<HttpPrincipal> user2 = - new User<HttpPrincipal>(new HttpPrincipal("User_2")); + final Collection<User> users = new ArrayList<User>(); - user2.details.add(new PersonalDetails("User", "Two")); + final User user1 = new User(); + URI uri1 = new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID()); + InternalID id1 = new InternalID(uri1); + TestUtil.setField(user1, id1, AbstractReaderWriter.ID); + users.add(user1); + final User user2 = new User(); + URI uri2 = new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID()); + InternalID id2 = new InternalID(uri2); + TestUtil.setField(user2, id2, AbstractReaderWriter.ID); + user2.personalDetails = new PersonalDetails("firstname", "lastname"); users.add(user2); userListWriter.write(users, writer); @@ -128,9 +136,7 @@ public class JsonUserListInputStreamWrapperTest testSubject.read(inputStream); - assertEquals("First item is wrong.", "CADCTest", - output.get(0).getUserID().getName()); - assertEquals("Second item is wrong.", "User_2", - output.get(1).getUserID().getName()); + assertEquals("First item is wrong.", id1, output.get(0).getID()); + assertEquals("Second item is wrong.", id2, output.get(1).getID()); } } diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/UserClientTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/UserClientTest.java index 966c2b64ae6f314480e0aed35f3368d27cc76811..067d5ab6b8f24d430ff5b063b41b3c483c8e0822 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/UserClientTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/UserClientTest.java @@ -72,8 +72,8 @@ package ca.nrc.cadc.ac.client; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; import java.security.Principal; +import java.util.UUID; import javax.management.remote.JMXPrincipal; import javax.security.auth.Subject; @@ -101,7 +101,6 @@ public class UserClientTest Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); } - @Test public void testConstructor() { @@ -109,31 +108,31 @@ public class UserClientTest try { new UserClient(null); - Assert.fail("Null base URL should throw an illegalArgumentException."); + Assert.fail("Null service URI should throw an illegalArgumentException."); } catch (IllegalArgumentException iae) { - Assert.assertEquals("baseURL is required", iae.getMessage()); + Assert.assertTrue(iae.getMessage().contains("cannot be null")); } catch (Throwable t) { Assert.fail("Unexpected exception: " + t.getMessage()); } - // case 2: test construction with a malformed URL + // case 2: serviceURI with a fragment try { - new UserClient("noSuchProtocol://localhost"); - Assert.fail("Malformed URL should throw an illegalArgumentException."); + URI uri = new URI("http://foo.com/bar?test#fragment"); + new UserClient(uri); + Assert.fail("Service URI containing a fragment should throw an illegalArgumentException."); } catch (IllegalArgumentException iae) { - Assert.assertTrue("Expecting 'URL is malformed'", - iae.getMessage().contains("URL is malformed")); + Assert.assertTrue(iae.getMessage().contains("fragment not allowed")); } catch (Throwable t) { - Assert.fail("Unexpected exception: " + t.getMessage()); + Assert.fail("Unexpected exception: " + t.getMessage()); } } @@ -180,9 +179,8 @@ public class UserClientTest protected UserClient createUserClient() throws URISyntaxException, MalformedURLException { RegistryClient regClient = new RegistryClient(); - URI serviceURI = new URI(AC.GMS_SERVICE_URI); - URL baseURL = regClient.getServiceURL(serviceURI, "https"); - return new UserClient(baseURL.toString()); + URI serviceURI = new URI(AC.UMS_SERVICE_URI); + return new UserClient(serviceURI); } @@ -191,9 +189,7 @@ public class UserClientTest { try { - RegistryClient rc = new RegistryClient(); - URL u = rc.getServiceURL(new URI("ivo://cadc.nrc.ca/canfargms")); - UserClient c = new UserClient(u.toString()); + UserClient c = new UserClient(new URI(AC.UMS_SERVICE_URI)); Subject s = new Subject(); s.getPrincipals().add(new HttpPrincipal("bob")); @@ -213,16 +209,15 @@ public class UserClientTest { try { - RegistryClient rc = new RegistryClient(); - URL u = rc.getServiceURL(new URI("ivo://cadc.nrc.ca/canfargms")); - UserClient c = new UserClient(u.toString()); + UserClient c = new UserClient(new URI(AC.UMS_SERVICE_URI)); Subject s = new Subject(); s.getPrincipals().add(new HttpPrincipal("bob")); - s.getPrincipals().add(new NumericPrincipal(1)); + UUID uuid = UUID.randomUUID(); + s.getPrincipals().add(new NumericPrincipal(uuid)); Principal p = c.getPrincipal(s); Assert.assertTrue(p instanceof NumericPrincipal); - Assert.assertEquals("1", p.getName()); + Assert.assertEquals(uuid.toString(), p.getName()); } catch (Throwable t) { @@ -236,16 +231,15 @@ public class UserClientTest { try { - RegistryClient rc = new RegistryClient(); - URL u = rc.getServiceURL(new URI("ivo://cadc.nrc.ca/canfargms")); - UserClient c = new UserClient(u.toString()); + UserClient c = new UserClient(new URI(AC.UMS_SERVICE_URI)); Subject s = new Subject(); - s.getPrincipals().add(new NumericPrincipal(1)); + UUID uuid = UUID.randomUUID(); + s.getPrincipals().add(new NumericPrincipal(uuid)); s.getPrincipals().add(new HttpPrincipal("bob")); Principal p = c.getPrincipal(s); Assert.assertTrue(p instanceof NumericPrincipal); - Assert.assertEquals("1", p.getName()); + Assert.assertEquals(uuid.toString(), p.getName()); } catch (Throwable t) { @@ -259,12 +253,11 @@ public class UserClientTest { try { - RegistryClient rc = new RegistryClient(); - URL u = rc.getServiceURL(new URI("ivo://cadc.nrc.ca/canfargms")); - UserClient c = new UserClient(u.toString()); + UserClient c = new UserClient(new URI(AC.UMS_SERVICE_URI)); Subject s = new Subject(); - s.getPrincipals().add(new NumericPrincipal(1)); + UUID uuid = UUID.randomUUID(); + s.getPrincipals().add(new NumericPrincipal(uuid)); s.getPrincipals().add(new X500Principal("CN=majorb")); s.getPrincipals().add(new HttpPrincipal("bob")); Principal p = c.getPrincipal(s); diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonGroupReaderWriterTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonGroupReaderWriterTest.java index 044046d8e9dbad0acb18061f91a8d3f0c2bde84f..e2079a714ad88a7c7aba053229e1c4bdc5e64c7a 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonGroupReaderWriterTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonGroupReaderWriterTest.java @@ -68,39 +68,48 @@ */ package ca.nrc.cadc.ac.json; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import javax.security.auth.x500.X500Principal; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.BeforeClass; +import org.junit.Test; + import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupProperty; +import ca.nrc.cadc.ac.InternalID; import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.PosixDetails; +import ca.nrc.cadc.ac.TestUtil; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.WriterException; +import ca.nrc.cadc.ac.xml.AbstractReaderWriter; import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.auth.OpenIdPrincipal; import ca.nrc.cadc.util.Log4jInit; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.junit.BeforeClass; -import org.junit.Test; - -import javax.security.auth.x500.X500Principal; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.security.Principal; -import java.util.*; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; /** * @author jburke */ public class JsonGroupReaderWriterTest { - private static Logger log = Logger - .getLogger(JsonGroupReaderWriterTest.class); + private static Logger log = Logger.getLogger(JsonGroupReaderWriterTest.class); @BeforeClass public static void setUpClass() @@ -181,7 +190,11 @@ public class JsonGroupReaderWriterTest public void testMaximalReadWrite() throws Exception { - User<Principal> owner = new User<Principal>(new HttpPrincipal("foo")); + User owner = new User(); + UUID uuid = UUID.randomUUID(); + URI uri = new URI("ivo://cadc.nrc.ca/user?" +uuid); + TestUtil.setField(owner, new InternalID(uri), AbstractReaderWriter.ID); + X500Principal x500Principal = new X500Principal("cn=foo,o=bar"); owner.getIdentities().add(x500Principal); PersonalDetails personalDetails = new PersonalDetails("foo", "bar"); @@ -190,21 +203,29 @@ public class JsonGroupReaderWriterTest personalDetails.institute = "institute"; personalDetails.city = "city"; personalDetails.country = "country"; - owner.details.add(personalDetails); - PosixDetails posixDetails = new PosixDetails(123L, 456L, "/dev/null"); - owner.details.add(posixDetails); + owner.personalDetails = personalDetails; + PosixDetails posixDetails = new PosixDetails("foo", 123L, 456L, "/dev/null"); + owner.posixDetails = posixDetails; + + Group expected = new Group("groupID"); + - Group expected = new Group("groupID", owner); expected.description = "description"; expected.lastModified = new Date(); expected.getProperties().add(new GroupProperty("key1", "value1", true)); expected.getProperties().add(new GroupProperty("key2", "value2", true)); expected.getProperties().add(new GroupProperty("key3", "value3", true)); - Group groupMember = new Group("member", new User<Principal>(new OpenIdPrincipal("bar"))); - User<Principal> userMember = new User<Principal>(new HttpPrincipal("baz")); - Group groupAdmin = new Group("admin", new User<Principal>(new X500Principal("cn=foo,o=ca"))); - User<Principal> userAdmin = new User<Principal>(new HttpPrincipal("admin")); + Group groupMember = new Group("member"); + User userMember = new User(); + userMember.getIdentities().add(new HttpPrincipal("foo")); + URI memberUri = new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID()); + TestUtil.setField(userMember, new InternalID(memberUri), AbstractReaderWriter.ID); + Group groupAdmin = new Group("admin"); + User userAdmin = new User(); + userAdmin.getIdentities().add(new HttpPrincipal("bar")); + URI adminUri = new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID()); + TestUtil.setField(userAdmin, new InternalID(adminUri), AbstractReaderWriter.ID); expected.getGroupMembers().add(groupMember); expected.getUserMembers().add(userMember); @@ -238,8 +259,10 @@ public class JsonGroupReaderWriterTest assertEquals(expected.lastModified, actual.lastModified); assertEquals("Properties don't match.", sortedExpectedProperties, sortedActualProperties); - assertEquals(expected.getGroupMembers(), actual.getGroupMembers()); - assertEquals(expected.getUserMembers(), actual.getUserMembers()); + assertTrue(expected.getGroupMembers().containsAll(actual.getGroupMembers())); + assertTrue(actual.getGroupMembers().containsAll(expected.getGroupMembers())); + assertTrue(expected.getUserMembers().containsAll(actual.getUserMembers())); + assertTrue(actual.getUserMembers().containsAll(expected.getUserMembers())); } class GroupPropertyComparator implements Comparator<GroupProperty> diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserListReaderWriterTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserListReaderWriterTest.java index faa4516743687d1804ab79162b68d3464546874a..c03f4b01c456e8e3ca165d9e1cad280f613d273a 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserListReaderWriterTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserListReaderWriterTest.java @@ -1,9 +1,12 @@ package ca.nrc.cadc.ac.json; +import ca.nrc.cadc.ac.InternalID; import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.PosixDetails; +import ca.nrc.cadc.ac.TestUtil; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.WriterException; +import ca.nrc.cadc.ac.xml.AbstractReaderWriter; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.util.Log4jInit; @@ -12,6 +15,7 @@ import org.junit.Test; import org.skyscreamer.jsonassert.JSONAssert; import java.io.*; +import java.net.URI; import java.security.Principal; import java.util.*; import org.apache.log4j.Level; @@ -78,54 +82,53 @@ public class JsonUserListReaderWriterTest * * @throws Exception */ - @Test - public void testWriter() throws Exception - { - final JsonUserListWriter testSubject = new JsonUserListWriter(); - - final List<User<HttpPrincipal>> users = - new ArrayList<User<HttpPrincipal>>(); - final Writer writer = new StringWriter(); - - for (int i = 0; i < 4; i++) - { - final User<HttpPrincipal> user = new User<HttpPrincipal>( - new HttpPrincipal("u"+Integer.toString(i))); - - user.details.add(new PersonalDetails("f"+Integer.toString(i), - "NUMBER_")); - - if ((i % 2) == 0) - { - user.details.add(new PosixDetails(88l + i, 88l + i, "/tmp")); - } - - users.add(user); - } - - testSubject.write(users, writer); - - final JSONObject expected = - new JSONObject("{\"users\":{\"$\":[" + - "{\"details\":{\"$\":[{\"firstName\":{\"$\":\"f0\"},\"lastName\":{\"$\":\"NUMBER_\"},\"@type\":\"personalDetails\"},{\"uid\":{\"$\":88},\"gid\":{\"$\":88},\"homeDirectory\":{\"$\":\"/tmp\"},\"@type\":\"posixDetails\"}]},\"userID\":{\"identity\":{\"$\":\"u0\",\"@type\":\"HTTP\"}}}," + - "{\"details\":{\"$\":[{\"firstName\":{\"$\":\"f1\"},\"lastName\":{\"$\":\"NUMBER_\"},\"@type\":\"personalDetails\"}]},\"userID\":{\"identity\":{\"$\":\"u1\",\"@type\":\"HTTP\"}}}," + - "{\"details\":{\"$\":[{\"uid\":{\"$\":90},\"gid\":{\"$\":90},\"homeDirectory\":{\"$\":\"/tmp\"},\"@type\":\"posixDetails\"},{\"firstName\":{\"$\":\"f2\"},\"lastName\":{\"$\":\"NUMBER_\"},\"@type\":\"personalDetails\"}]},\"userID\":{\"identity\":{\"$\":\"u2\",\"@type\":\"HTTP\"}}}," + - "{\"details\":{\"$\":[{\"firstName\":{\"$\":\"f3\"},\"lastName\":{\"$\":\"NUMBER_\"},\"@type\":\"personalDetails\"}]},\"userID\":{\"identity\":{\"$\":\"u3\",\"@type\":\"HTTP\"}}}]}}"); - - String json = writer.toString(); - log.debug("user list:\n" + json); - final JSONObject result = new JSONObject(json); - - JSONAssert.assertEquals(expected, result, false); - - JsonUserListReader reader = new JsonUserListReader(); - - final InputStream in = - new ByteArrayInputStream(expected.toString().getBytes()); - final Collection<User<Principal>> readBackIn = reader.read(in); - - assertEquals("Size is wrong.", 4, readBackIn.size()); - } +// @Test +// public void testWriter() throws Exception +// { +// final JsonUserListWriter testSubject = new JsonUserListWriter(); +// +// final List<User> users = new ArrayList<User>(); +// final Writer writer = new StringWriter(); +// +// for (int i = 0; i < 4; i++) +// { +// final User user = new User( +// new HttpPrincipal("u"+Integer.toString(i))); +// +// user.details.add(new PersonalDetails("f"+Integer.toString(i), +// "NUMBER_")); +// +// if ((i % 2) == 0) +// { +// user.details.add(new PosixDetails(88l + i, 88l + i, "/tmp")); +// } +// +// users.add(user); +// } +// +// testSubject.write(users, writer); +// +// final JSONObject expected = +// new JSONObject("{\"users\":{\"$\":[" + +// "{\"details\":{\"$\":[{\"firstName\":{\"$\":\"f0\"},\"lastName\":{\"$\":\"NUMBER_\"},\"@type\":\"personalDetails\"},{\"uid\":{\"$\":88},\"gid\":{\"$\":88},\"homeDirectory\":{\"$\":\"/tmp\"},\"@type\":\"posixDetails\"}]},\"userID\":{\"identity\":{\"$\":\"u0\",\"@type\":\"HTTP\"}}}," + +// "{\"details\":{\"$\":[{\"firstName\":{\"$\":\"f1\"},\"lastName\":{\"$\":\"NUMBER_\"},\"@type\":\"personalDetails\"}]},\"userID\":{\"identity\":{\"$\":\"u1\",\"@type\":\"HTTP\"}}}," + +// "{\"details\":{\"$\":[{\"uid\":{\"$\":90},\"gid\":{\"$\":90},\"homeDirectory\":{\"$\":\"/tmp\"},\"@type\":\"posixDetails\"},{\"firstName\":{\"$\":\"f2\"},\"lastName\":{\"$\":\"NUMBER_\"},\"@type\":\"personalDetails\"}]},\"userID\":{\"identity\":{\"$\":\"u2\",\"@type\":\"HTTP\"}}}," + +// "{\"details\":{\"$\":[{\"firstName\":{\"$\":\"f3\"},\"lastName\":{\"$\":\"NUMBER_\"},\"@type\":\"personalDetails\"}]},\"userID\":{\"identity\":{\"$\":\"u3\",\"@type\":\"HTTP\"}}}]}}"); +// +// String json = writer.toString(); +// log.debug("user list:\n" + json); +// final JSONObject result = new JSONObject(json); +// +// JSONAssert.assertEquals(expected, result, false); +// +// JsonUserListReader reader = new JsonUserListReader(); +// +// final InputStream in = +// new ByteArrayInputStream(expected.toString().getBytes()); +// final Collection<User<Principal>> readBackIn = reader.read(in); +// +// assertEquals("Size is wrong.", 4, readBackIn.size()); +// } @Test public void testWriterExceptions() @@ -147,10 +150,19 @@ public class JsonUserListReaderWriterTest public void testReadWrite() throws Exception { - User<Principal> expected = new User<Principal>(new HttpPrincipal("foo")); - expected.getIdentities().add(new NumericPrincipal(123)); - expected.details.add(new PersonalDetails("firstname", "lastname")); - expected.details.add(new PosixDetails(123l, 456l, "foo")); + User expected = new User(); + UUID uuid = UUID.randomUUID(); + URI uri = new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID()); + TestUtil.setField(expected, new InternalID(uri), AbstractReaderWriter.ID); + + expected.getIdentities().add(new NumericPrincipal(uuid)); + expected.personalDetails = new PersonalDetails("firstname", "lastname"); + expected.personalDetails.address = "address"; + expected.personalDetails.city = "city"; + expected.personalDetails.country = "country"; + expected.personalDetails.email = "foo@bar.com"; + expected.personalDetails.institute = "institute"; + expected.posixDetails = new PosixDetails("bar", 123l, 456l, "/dev/null"); StringBuilder json = new StringBuilder(); JsonUserWriter writer = new JsonUserWriter(); @@ -158,7 +170,7 @@ public class JsonUserListReaderWriterTest assertFalse(json.toString().isEmpty()); JsonUserReader reader = new JsonUserReader(); - User<Principal> actual = reader.read(json.toString()); + User actual = reader.read(json.toString()); assertNotNull(actual); assertEquals(expected, actual); } diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserReaderWriterTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserReaderWriterTest.java index d18ba230754fbbfd82b063a47decdd50d5f30aa5..dd88de293772a27f73e56daae329291486ced152 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserReaderWriterTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserReaderWriterTest.java @@ -68,11 +68,13 @@ */ package ca.nrc.cadc.ac.json; +import ca.nrc.cadc.ac.InternalID; import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.PosixDetails; +import ca.nrc.cadc.ac.TestUtil; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.WriterException; -import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.ac.xml.AbstractReaderWriter; import ca.nrc.cadc.auth.NumericPrincipal; import org.apache.log4j.Logger; import org.junit.Test; @@ -80,7 +82,8 @@ import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.io.Reader; -import java.security.Principal; +import java.net.URI; +import java.util.UUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -103,7 +106,7 @@ public class JsonUserReaderWriterTest { String s = null; JsonUserReader reader = new JsonUserReader(); - User<Principal> u = reader.read(s); + User u = reader.read(s); fail("null String should throw IllegalArgumentException"); } catch (IllegalArgumentException e) {} @@ -112,7 +115,7 @@ public class JsonUserReaderWriterTest { InputStream in = null; JsonUserReader reader = new JsonUserReader(); - User<Principal> u = reader.read(in); + User u = reader.read(in); fail("null InputStream should throw IOException"); } catch (IOException e) {} @@ -121,7 +124,7 @@ public class JsonUserReaderWriterTest { Reader r = null; JsonUserReader reader = new JsonUserReader(); - User<Principal> u = reader.read(r); + User u = reader.read(r); fail("null Reader should throw IllegalArgumentException"); } catch (IllegalArgumentException e) {} @@ -144,10 +147,14 @@ public class JsonUserReaderWriterTest public void testReadWrite() throws Exception { - User<? extends Principal> expected = new User<Principal>(new HttpPrincipal("foo")); - expected.getIdentities().add(new NumericPrincipal(123)); - expected.details.add(new PersonalDetails("firstname", "lastname")); - expected.details.add(new PosixDetails(123l, 456l, "foo")); + User expected = new User(); + UUID uuid = UUID.randomUUID(); + URI uri = new URI("ivo://cadc.nrc.ca/user?" + uuid); + TestUtil.setField(expected, new InternalID(uri), AbstractReaderWriter.ID); + + expected.getIdentities().add(new NumericPrincipal(uuid)); + expected.personalDetails = new PersonalDetails("firstname", "lastname"); + expected.posixDetails = new PosixDetails("foo", 123l, 456l, "/dev/null"); StringBuilder json = new StringBuilder(); JsonUserWriter writer = new JsonUserWriter(); @@ -155,7 +162,7 @@ public class JsonUserReaderWriterTest assertFalse(json.toString().isEmpty()); JsonUserReader reader = new JsonUserReader(); - User<Principal> actual = reader.read(json.toString()); + User actual = reader.read(json.toString()); assertNotNull(actual); assertEquals(expected, actual); } diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserRequestReaderWriterTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserRequestReaderWriterTest.java index cd4f6e715dd2a66723ed7a7d612806813b2dea00..f383d07b46f6ce302ceb5692dfb0a8e24af5be44 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserRequestReaderWriterTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/json/JsonUserRequestReaderWriterTest.java @@ -67,17 +67,22 @@ */ package ca.nrc.cadc.ac.json; +import ca.nrc.cadc.ac.InternalID; import ca.nrc.cadc.ac.PersonalDetails; +import ca.nrc.cadc.ac.TestUtil; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserRequest; import ca.nrc.cadc.ac.WriterException; +import ca.nrc.cadc.ac.xml.AbstractReaderWriter; import ca.nrc.cadc.auth.HttpPrincipal; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.net.URI; import java.security.Principal; +import java.util.UUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -136,12 +141,14 @@ public class JsonUserRequestReaderWriterTest public void testReadWrite() throws Exception { - User<Principal> expectedUser = - new User<Principal>(new HttpPrincipal("CADCtest")); - expectedUser.details.add(new PersonalDetails("CADCtest", "User")); + User expectedUser = new User(); + URI uri = new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID()); + TestUtil.setField(expectedUser, new InternalID(uri), AbstractReaderWriter.ID); - UserRequest<Principal> expected = - new UserRequest<Principal>(expectedUser, "MYPASSWORD".toCharArray()); + expectedUser.getIdentities().add(new HttpPrincipal("foo")); + expectedUser.personalDetails = new PersonalDetails("CADCtest", "User"); + + UserRequest expected = new UserRequest(expectedUser, "MYPASSWORD".toCharArray()); StringBuilder json = new StringBuilder(); JsonUserRequestWriter writer = new JsonUserRequestWriter(); @@ -149,7 +156,7 @@ public class JsonUserRequestReaderWriterTest assertFalse(json.toString().isEmpty()); JsonUserRequestReader reader = new JsonUserRequestReader(); - UserRequest<Principal> actual = reader.read(json.toString()); + UserRequest actual = reader.read(json.toString()); assertNotNull(actual); assertEquals(expected, actual); } diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupListReaderWriterTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupListReaderWriterTest.java index a18c13b3c093922e9da73774004296729eb0cf70..60331f5a132eb14c74eaeaa1f6ef0d21e19fe603 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupListReaderWriterTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupListReaderWriterTest.java @@ -142,8 +142,8 @@ public class GroupListReaderWriterTest throws Exception { List<Group> expected = new ArrayList<Group>(); - expected.add(new Group("group1", null)); - expected.add(new Group("group2", null)); + expected.add(new Group("group1")); + expected.add(new Group("group2")); StringBuilder xml = new StringBuilder(); GroupListWriter groupListWriter = new GroupListWriter(); diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupReaderWriterTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupReaderWriterTest.java index 6aab545506a02e5be27e23a648289c284eef17a5..ee219c9c822927eceb21728a9c69665fb6bd4019 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupReaderWriterTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupReaderWriterTest.java @@ -68,28 +68,34 @@ */ package ca.nrc.cadc.ac.xml; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.lang.reflect.Field; +import java.net.URI; +import java.util.Date; +import java.util.UUID; + +import javax.security.auth.x500.X500Principal; + +import org.apache.log4j.Logger; +import org.junit.Test; + import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupProperty; +import ca.nrc.cadc.ac.InternalID; import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.PosixDetails; +import ca.nrc.cadc.ac.TestUtil; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.WriterException; import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.auth.OpenIdPrincipal; -import org.apache.log4j.Logger; -import org.junit.Test; - -import javax.security.auth.x500.X500Principal; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.security.Principal; -import java.util.Date; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; /** * @@ -111,7 +117,7 @@ public class GroupReaderWriterTest fail("null String should throw IllegalArgumentException"); } catch (IllegalArgumentException e) {} - + try { InputStream in = null; @@ -120,7 +126,7 @@ public class GroupReaderWriterTest fail("null InputStream should throw IOException"); } catch (IOException e) {} - + try { Reader r = null; @@ -130,7 +136,7 @@ public class GroupReaderWriterTest } catch (IllegalArgumentException e) {} } - + @Test public void testWriterExceptions() throws Exception @@ -143,13 +149,13 @@ public class GroupReaderWriterTest } catch (WriterException e) {} } - + @Test public void testMinimalReadWrite() throws Exception { - Group expected = new Group("groupID", null); - + Group expected = new Group("groupID"); + StringBuilder xml = new StringBuilder(); GroupWriter groupWriter = new GroupWriter(); groupWriter.write(expected, xml); @@ -160,40 +166,46 @@ public class GroupReaderWriterTest assertNotNull(actual); assertEquals(expected, actual); } - + @Test public void testMaximalReadWrite() throws Exception { - User<Principal> owner = new User<Principal>(new HttpPrincipal("foo")); + User owner = new User(); X500Principal x500Principal = new X500Principal("cn=foo,o=bar"); owner.getIdentities().add(x500Principal); - PersonalDetails personalDetails = new PersonalDetails("foo", "bar"); - personalDetails.address = "address"; - personalDetails.email = "email"; - personalDetails.institute = "institute"; - personalDetails.city = "city"; - personalDetails.country = "country"; - owner.details.add(personalDetails); - PosixDetails posixDetails = new PosixDetails(123L, 456L, "/dev/null"); - owner.details.add(posixDetails); - - Group expected = new Group("groupID", owner); + owner.personalDetails = new PersonalDetails("foo", "bar"); + owner.personalDetails.address = "address"; + owner.personalDetails.email = "email"; + owner.personalDetails.institute = "institute"; + owner.personalDetails.city = "city"; + owner.personalDetails.country = "country"; + owner.posixDetails = new PosixDetails("foo", 123L, 456L, "/dev/null"); + + Group expected = new Group("groupID"); + setGroupOwner(expected, owner); expected.description = "description"; expected.lastModified = new Date(); expected.getProperties().add(new GroupProperty("key1", "value1", true)); expected.getProperties().add(new GroupProperty("key2", "value2", false)); - - Group groupMember = new Group("member", new User<Principal>(new OpenIdPrincipal("bar"))); - User<Principal> userMember = new User<Principal>(new HttpPrincipal("baz")); - Group groupAdmin = new Group("admin", new User<Principal>(new X500Principal("cn=foo,o=ca"))); - User<Principal> userAdmin = new User<Principal>(new HttpPrincipal("admin")); - + + Group groupMember = new Group("member"); + User userMember = new User(); + userMember.getIdentities().add(new HttpPrincipal("foo")); + URI memberUri = new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID()); + TestUtil.setField(userMember, new InternalID(memberUri), AbstractReaderWriter.ID); + + Group groupAdmin = new Group("admin"); + User userAdmin = new User(); + userAdmin.getIdentities().add(new HttpPrincipal("bar")); + URI adminUri = new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID()); + TestUtil.setField(userAdmin, new InternalID(adminUri), AbstractReaderWriter.ID); + expected.getGroupMembers().add(groupMember); expected.getUserMembers().add(userMember); expected.getGroupAdmins().add(groupAdmin); expected.getUserAdmins().add(userAdmin); - + StringBuilder xml = new StringBuilder(); GroupWriter groupWriter = new GroupWriter(); groupWriter.write(expected, xml); @@ -206,8 +218,29 @@ public class GroupReaderWriterTest assertEquals(expected.description, actual.description); assertEquals(expected.lastModified, actual.lastModified); assertEquals(expected.getProperties(), actual.getProperties()); - assertEquals(expected.getGroupMembers(), actual.getGroupMembers()); - assertEquals(expected.getUserMembers(), actual.getUserMembers()); + assertTrue(expected.getGroupMembers().containsAll(actual.getGroupMembers())); + assertTrue(actual.getGroupMembers().containsAll(expected.getGroupMembers())); + assertTrue(expected.getUserMembers().containsAll(actual.getUserMembers())); + assertTrue(actual.getUserMembers().containsAll(expected.getUserMembers())); + } + + private void setGroupOwner(Group group, User owner) + { + // set private uri field using reflection + try + { + Field field = group.getClass().getDeclaredField("owner"); + field.setAccessible(true); + field.set(group, owner); + } + catch (NoSuchFieldException e) + { + throw new RuntimeException("Group owner field not found", e); + } + catch (IllegalAccessException e) + { + throw new RuntimeException("unable to update Group owner field", e); + } } - + } diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/IdentityReaderWriterTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/IdentityReaderWriterTest.java index 9fec0915d6bb4bdabc81453a1f9772f2be4a5b25..13f31fa0195b212923c35cfc9129e82ff1abaa73 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/IdentityReaderWriterTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/IdentityReaderWriterTest.java @@ -80,6 +80,7 @@ import org.junit.Test; import javax.management.remote.JMXPrincipal; import javax.security.auth.x500.X500Principal; import java.security.Principal; +import java.util.UUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -166,7 +167,7 @@ public class IdentityReaderWriterTest extends AbstractReaderWriter assertEquals(expected, actual); // CADC - expected = new NumericPrincipal(123); + expected = new NumericPrincipal(UUID.randomUUID()); element = getElement(expected); assertNotNull(element); diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserDetailsReaderWriterTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserDetailsReaderWriterTest.java index 4a6304dd4e31fa88ccb2fd34f53c46164972ce27..e49735de1aa62767adb19b451dcfdc510bc54cb7 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserDetailsReaderWriterTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserDetailsReaderWriterTest.java @@ -71,7 +71,6 @@ package ca.nrc.cadc.ac.xml; import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.PosixDetails; import ca.nrc.cadc.ac.ReaderException; -import ca.nrc.cadc.ac.UserDetails; import ca.nrc.cadc.ac.WriterException; import org.apache.log4j.Logger; import org.jdom2.Element; @@ -96,7 +95,7 @@ public class UserDetailsReaderWriterTest extends AbstractReaderWriter Element element = null; try { - UserDetails ud = getUserDetails(element); + PersonalDetails pd = getPersonalDetails(element); fail("null element should throw ReaderException"); } catch (ReaderException e) {} @@ -104,24 +103,24 @@ public class UserDetailsReaderWriterTest extends AbstractReaderWriter element = new Element("foo"); try { - UserDetails ud = getUserDetails(element); - fail("element not named 'userDetails' should throw ReaderException"); + PersonalDetails pd = getPersonalDetails(element); + fail("element not named 'personalDetails' should throw ReaderException"); } catch (ReaderException e) {} - - element = new Element(UserDetails.NAME); + + element = null; try { - UserDetails ud = getUserDetails(element); - fail("element without 'type' attribute should throw ReaderException"); + PosixDetails pd = getPosixDetails(element); + fail("null element should throw ReaderException"); } catch (ReaderException e) {} - - element.setAttribute("type", "foo"); + + element = new Element("foo"); try { - UserDetails ud = getUserDetails(element); - fail("element with unknown 'type' attribute should throw ReaderException"); + PosixDetails pd = getPosixDetails(element); + fail("element not named 'posixDetails' should throw ReaderException"); } catch (ReaderException e) {} } @@ -132,9 +131,17 @@ public class UserDetailsReaderWriterTest extends AbstractReaderWriter { try { - UserDetails ud = null; - Element element = getElement(ud); - fail("null UserDetails should throw WriterException"); + PersonalDetails pd = null; + Element element = getElement(pd); + fail("null PersonalDetails should throw WriterException"); + } + catch (WriterException e) {} + + try + { + PosixDetails pd = null; + Element element = getElement(pd); + fail("null PosixDetails should throw WriterException"); } catch (WriterException e) {} } @@ -152,7 +159,7 @@ public class UserDetailsReaderWriterTest extends AbstractReaderWriter Element element = getElement(expected); assertNotNull(element); - PersonalDetails actual = (PersonalDetails) getUserDetails(element); + PersonalDetails actual = getPersonalDetails(element); assertNotNull(actual); assertEquals(expected, actual); assertEquals(expected.address, actual.address); @@ -166,11 +173,11 @@ public class UserDetailsReaderWriterTest extends AbstractReaderWriter public void testReadWritePosixDetails() throws Exception { - UserDetails expected = new PosixDetails(123l, 456, "/dev/null"); + PosixDetails expected = new PosixDetails("username", 123l, 456, "/dev/null"); Element element = getElement(expected); assertNotNull(element); - UserDetails actual = getUserDetails(element); + PosixDetails actual = getPosixDetails(element); assertNotNull(actual); assertEquals(expected, actual); } diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserListReaderWriterTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserListReaderWriterTest.java index ddca58a35b80651b347fb533e575b9f825a19b40..2f304d832de713ec02b2a9a7eea1756de6900fb9 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserListReaderWriterTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserListReaderWriterTest.java @@ -1,23 +1,26 @@ package ca.nrc.cadc.ac.xml; -import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.ac.WriterException; -import ca.nrc.cadc.auth.HttpPrincipal; -import org.apache.log4j.Logger; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; -import javax.security.auth.x500.X500Principal; import java.io.IOException; import java.io.InputStream; import java.io.Reader; -import java.security.Principal; +import java.net.URI; import java.util.ArrayList; import java.util.List; +import java.util.UUID; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; +import org.apache.log4j.Logger; +import org.junit.Test; + +import ca.nrc.cadc.ac.InternalID; +import ca.nrc.cadc.ac.TestUtil; +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.WriterException; +import ca.nrc.cadc.auth.HttpPrincipal; public class UserListReaderWriterTest { @@ -31,7 +34,7 @@ public class UserListReaderWriterTest { String s = null; UserListReader UserListReader = new UserListReader(); - List<User<Principal>> u = UserListReader.read(s); + List<User> u = UserListReader.read(s); fail("null String should throw IllegalArgumentException"); } catch (IllegalArgumentException e) {} @@ -40,7 +43,7 @@ public class UserListReaderWriterTest { InputStream in = null; UserListReader userListReader = new UserListReader(); - List<User<Principal>> u = userListReader.read(in); + List<User> u = userListReader.read(in); fail("null InputStream should throw IOException"); } catch (IOException e) {} @@ -49,7 +52,7 @@ public class UserListReaderWriterTest { Reader r = null; UserListReader userListReader = new UserListReader(); - List<User<Principal>> u = userListReader.read(r); + List<User> u = userListReader.read(r); fail("null element should throw ReaderException"); } catch (IllegalArgumentException e) {} @@ -72,9 +75,19 @@ public class UserListReaderWriterTest public void testMinimalReadWrite() throws Exception { - List<User<Principal>> expected = new ArrayList<User<Principal>>(); - expected.add(new User<Principal>(new HttpPrincipal("foo"))); - expected.add(new User<Principal>(new X500Principal("cn=foo,o=bar"))); + List<User> expected = new ArrayList<User>(); + + User user1 = new User(); + user1.getIdentities().add(new HttpPrincipal("foo")); + InternalID id1 = new InternalID(new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID())); + TestUtil.setField(user1, id1, AbstractReaderWriter.ID); + expected.add(user1); + + User user2 = new User(); + user2.getIdentities().add(new HttpPrincipal("foo")); + InternalID id2 = new InternalID(new URI("ivo://cadc.nrc.ca/user?" + UUID.randomUUID())); + TestUtil.setField(user2, id2, AbstractReaderWriter.ID); + expected.add(user2); StringBuilder xml = new StringBuilder(); UserListWriter userListWriter = new UserListWriter(); @@ -82,7 +95,7 @@ public class UserListReaderWriterTest assertFalse(xml.toString().isEmpty()); UserListReader userListReader = new UserListReader(); - List<User<Principal>> actual = userListReader.read(xml.toString()); + List<User> actual = userListReader.read(xml.toString()); assertNotNull(actual); assertEquals(expected.size(), actual.size()); assertEquals(expected.get(0), actual.get(0)); diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserReaderWriterTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserReaderWriterTest.java index 696a7c8169c61e1d62e792a5378e5af90bd2b9bb..5c496d2239fcbed9419a6623a9bb6600d8f09b2a 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserReaderWriterTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserReaderWriterTest.java @@ -68,10 +68,11 @@ */ package ca.nrc.cadc.ac.xml; +import ca.nrc.cadc.ac.InternalID; import ca.nrc.cadc.ac.PersonalDetails; +import ca.nrc.cadc.ac.TestUtil; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.WriterException; -import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; import org.apache.log4j.Logger; import org.junit.Test; @@ -79,7 +80,8 @@ import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.io.Reader; -import java.security.Principal; +import java.net.URI; +import java.util.UUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -102,7 +104,7 @@ public class UserReaderWriterTest { String s = null; UserReader userReader = new UserReader(); - User<Principal> u = userReader.read(s); + User u = userReader.read(s); fail("null String should throw IllegalArgumentException"); } catch (IllegalArgumentException e) {} @@ -111,7 +113,7 @@ public class UserReaderWriterTest { InputStream in = null; UserReader userReader = new UserReader(); - User<Principal> u = userReader.read(in); + User u = userReader.read(in); fail("null InputStream should throw IOException"); } catch (IOException e) {} @@ -120,7 +122,7 @@ public class UserReaderWriterTest { Reader r = null; UserReader userReader = new UserReader(); - User<Principal> u = userReader.read(r); + User u = userReader.read(r); fail("null Reader should throw IllegalArgumentException"); } catch (IllegalArgumentException e) {} @@ -143,9 +145,12 @@ public class UserReaderWriterTest public void testReadWrite() throws Exception { - User<Principal> expected = new User<Principal>(new HttpPrincipal("foo")); - expected.getIdentities().add(new NumericPrincipal(123)); - expected.details.add(new PersonalDetails("firstname", "lastname")); + User expected = new User(); + UUID uuid = UUID.randomUUID(); + URI uri = new URI("ivo://cadc.nrc.ca/user?" + uuid); + TestUtil.setField(expected, new InternalID(uri), AbstractReaderWriter.ID); + expected.getIdentities().add(new NumericPrincipal(uuid)); + expected.personalDetails = new PersonalDetails("firstname", "lastname"); StringBuilder xml = new StringBuilder(); UserWriter userWriter = new UserWriter(); @@ -153,7 +158,7 @@ public class UserReaderWriterTest assertFalse(xml.toString().isEmpty()); UserReader userReader = new UserReader(); - User<? extends Principal> actual = userReader.read(xml.toString()); + User actual = userReader.read(xml.toString()); assertNotNull(actual); assertEquals(expected, actual); } diff --git a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserRequestReaderWriterTest.java b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserRequestReaderWriterTest.java index 40fb65bd0292debc845299e66792da9e3febf9d6..f00295093c061ea251664bea85cefc666d4e0f79 100644 --- a/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserRequestReaderWriterTest.java +++ b/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserRequestReaderWriterTest.java @@ -68,11 +68,12 @@ */ package ca.nrc.cadc.ac.xml; +import ca.nrc.cadc.ac.InternalID; import ca.nrc.cadc.ac.PersonalDetails; +import ca.nrc.cadc.ac.TestUtil; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserRequest; import ca.nrc.cadc.ac.WriterException; -import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; import org.apache.log4j.Logger; import org.junit.Test; @@ -80,9 +81,13 @@ import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.io.Reader; -import java.security.Principal; +import java.net.URI; +import java.util.UUID; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; /** * @@ -141,14 +146,18 @@ public class UserRequestReaderWriterTest public void testReadWrite() throws Exception { - User<HttpPrincipal> expectedUser = new User<HttpPrincipal>(new HttpPrincipal("foo")); - expectedUser.getIdentities().add(new NumericPrincipal(123)); - expectedUser.details.add(new PersonalDetails("firstname", "lastname")); + User expectedUser = new User(); + UUID uuid = UUID.randomUUID(); + URI uri = new URI("ivo://cadc.nrc.ca/user?" + uuid); + TestUtil.setField(expectedUser, new InternalID(uri), AbstractReaderWriter.ID); + + expectedUser.getIdentities().add(new NumericPrincipal(uuid)); + expectedUser.personalDetails = new PersonalDetails("firstname", "lastname"); char[] expectedPassword = "123456".toCharArray(); - UserRequest<HttpPrincipal> expected = - new UserRequest<HttpPrincipal>(expectedUser, expectedPassword); + UserRequest expected = + new UserRequest(expectedUser, expectedPassword); StringBuilder xml = new StringBuilder(); UserRequestWriter userRequestWriter = new UserRequestWriter(); diff --git a/cadcTomcat/src/ca/nrc/cadc/tomcat/CadcBasicAuthenticator.java b/cadcTomcat/src/ca/nrc/cadc/tomcat/CadcBasicAuthenticator.java index a6d5615c3e1a87ca13a0e18aae195434d01bf361..d27a2f83476821f3a0b66631f314710452fe4322 100644 --- a/cadcTomcat/src/ca/nrc/cadc/tomcat/CadcBasicAuthenticator.java +++ b/cadcTomcat/src/ca/nrc/cadc/tomcat/CadcBasicAuthenticator.java @@ -98,7 +98,7 @@ public class CadcBasicAuthenticator extends RealmBase { private static Logger log = Logger.getLogger(CadcBasicAuthenticator.class); - private static final String AC_URI = "ivo://cadc.nrc.ca/canfargms"; + private static final String AC_URI = "ivo://canfar.net/ums"; static { @@ -177,7 +177,7 @@ public class CadcBasicAuthenticator extends RealmBase { RealmRegistryClient registryClient = new RealmRegistryClient(); URL loginURL = registryClient.getServiceURL( - new URI(AC_URI), "http", "/login"); + new URI(AC_URI + "#login"), "http", ""); String post = "username=" + username + "&password=" + credentials; @@ -213,4 +213,4 @@ public class CadcBasicAuthenticator extends RealmBase -} \ No newline at end of file +}