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..37482c058b8e85063d93f029539e9bd32eed84c8 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 @@ -100,6 +100,13 @@ public class LdapConnectionPool { private static final Logger logger = Logger.getLogger(LdapConnectionPool.class); + private enum SystemState + { + ONLINE, + READONLY, + OFFLINE + }; + Profiler profiler = new Profiler(LdapConnectionPool.class); protected LdapConfig currentConfig; @@ -107,8 +114,10 @@ public class LdapConnectionPool private LDAPConnectionPool pool; private Object poolMonitor = new Object(); private LDAPConnectionOptions connectionOptions; + private boolean readOnly; + SystemState systemState = SystemState.ONLINE; - 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,19 +131,49 @@ public class LdapConnectionPool connectionOptions.setAutoReconnect(true); currentConfig = config; this.poolName = poolName; - synchronized (poolMonitor) + this.readOnly = readOnly; + + systemState = getSystemState(config); + 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."); + 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 { LDAPConnection conn = null; @@ -169,8 +208,11 @@ public class LdapConnectionPool public void releaseConnection(LDAPConnection conn) { - pool.releaseConnection(conn); - logger.debug(poolName + " pool statistics after release:\n" + pool.getConnectionPoolStatistics()); + if (pool != null) + { + pool.releaseConnection(conn); + logger.debug(poolName + " pool statistics after release:\n" + pool.getConnectionPoolStatistics()); + } } public LdapConfig getCurrentConfig() @@ -180,9 +222,12 @@ public class LdapConnectionPool public void shutdown() { - logger.debug("Closing pool..."); - pool.close(); - profiler.checkpoint("Pool closed."); + if (pool != null) + { + logger.debug("Closing pool..."); + pool.close(); + profiler.checkpoint("Pool closed."); + } } public String getName() @@ -191,7 +236,6 @@ public class LdapConnectionPool } private LDAPConnectionPool createPool(LdapConfig config, LdapPool poolConfig, String poolName, String bindID, String bindPW) - { try { @@ -245,4 +289,32 @@ public class LdapConnectionPool } + /** + * 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. + */ + private SystemState getSystemState(LdapConfig config) + { + + if (config.getReadOnlyPool().getMaxSize() == 0) + { + return SystemState.OFFLINE; + } + + if (config.getUnboundReadOnlyPool().getMaxSize() == 0) + { + return SystemState.OFFLINE; + } + + if (config.getReadWritePool().getMaxSize() == 0) + { + return SystemState.READONLY; + } + + return SystemState.ONLINE; + } + + } 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..cf5451e997fc29f48711ae72f3a77586669975c2 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 @@ -147,7 +147,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) { @@ -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) { @@ -225,7 +225,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) { @@ -317,4 +317,5 @@ class LdapConnections return config; } + } 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..50e9176bd5b77722124391c49e52fdcaf9fa696b 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; @@ -87,11 +93,6 @@ import ca.nrc.cadc.auth.AuthMethod; import ca.nrc.cadc.auth.AuthenticationUtil; import ca.nrc.cadc.auth.DNPrincipal; 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; public class LdapGroupPersistence<T extends Principal> extends LdapPersistence implements GroupPersistence<T> { @@ -125,7 +126,7 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i 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; LdapConnections conns = new LdapConnections(this); @@ -148,7 +149,7 @@ 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; LdapConnections conns = new LdapConnections(this); @@ -175,7 +176,7 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i Subject caller = AuthenticationUtil.getCurrentSubject(); User<Principal> owner = getUser(caller); group.setOwner(owner); - + LdapConnections conns = new LdapConnections(this); try { @@ -194,7 +195,7 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i AccessControlException { Subject callerSubject = AuthenticationUtil.getCurrentSubject(); - + LdapGroupDAO<T> groupDAO = null; LdapUserDAO<T> userDAO = null; LdapConnections conns = new LdapConnections(this); @@ -203,7 +204,7 @@ public class LdapGroupPersistence<T extends Principal> extends LdapPersistence i userDAO = new LdapUserDAO<T>(conns); groupDAO = new LdapGroupDAO<T>(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,7 +221,7 @@ 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; LdapConnections conns = new LdapConnections(this); @@ -247,27 +248,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); - + if ( Role.OWNER.equals(role)) { DNPrincipal p = getInternalID(caller); @@ -316,20 +317,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 +342,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 +353,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,18 +375,18 @@ 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) { 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"); 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..2e7c75da3e6bdd3cc2caf746ebcd16a461189415 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 @@ -115,7 +115,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) @@ -240,11 +240,11 @@ public abstract class LdapPersistence { 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)) { @@ -278,6 +278,7 @@ public abstract class LdapPersistence logger.debug("Detected ldap configuration change, rebuilding pools"); boolean poolRecreated = false; final ConnectionPools oldPools = pools; + ConnectionPools newPools = null; synchronized (jndiMonitor) { @@ -287,7 +288,7 @@ public abstract class LdapPersistence { try { - ConnectionPools newPools = createPools(newConfig); + newPools = createPools(newConfig); newPools.setLastPoolCheck(System.currentTimeMillis()); InitialContext ic = new InitialContext(); try @@ -326,9 +327,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/LdapUserPersistence.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java index add4f8246ed770e19a25a29c19353952dda6aaff..b3d24cd5f2f815dbd375e032ff5a2ab5eb6f77f0 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,8 +87,6 @@ import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.profiler.Profiler; -import javax.security.auth.Subject; - public class LdapUserPersistence<T extends Principal> extends LdapPersistence implements UserPersistence<T> { private static final Logger logger = Logger.getLogger(LdapUserPersistence.class); @@ -173,7 +173,7 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im Subject caller = AuthenticationUtil.getCurrentSubject(); if ( !isMatch(caller, userID) ) throw new AccessControlException("permission denied: target user does not match current user"); - + LdapUserDAO<T> userDAO = null; LdapConnections conns = new LdapConnections(this); try @@ -186,7 +186,7 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im conns.releaseConnections(); } } - + /** * Get the user specified by email address exists in the active users tree. * @@ -200,7 +200,7 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im * @throws UserAlreadyExistsException A user with the same email address already exists */ public User<Principal> getUserByEmailAddress(String emailAddress) - throws UserNotFoundException, TransientException, + throws UserNotFoundException, TransientException, AccessControlException, UserAlreadyExistsException { LdapConnections conns = new LdapConnections(this); @@ -230,7 +230,7 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im Subject caller = AuthenticationUtil.getCurrentSubject(); if ( !isMatch(caller, userID) ) throw new AccessControlException("permission denied: target user does not match current user"); - + LdapUserDAO<T> userDAO = null; LdapConnections conns = new LdapConnections(this); try @@ -289,7 +289,7 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im Subject caller = AuthenticationUtil.getCurrentSubject(); if (caller == null || AuthMethod.ANON.equals(AuthenticationUtil.getAuthMethod(caller))) throw new AccessControlException("Caller is not authenticated"); - + LdapUserDAO<T> userDAO = null; LdapConnections conns = new LdapConnections(this); try @@ -375,7 +375,7 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im Subject caller = AuthenticationUtil.getCurrentSubject(); if ( !isMatch(caller, user) ) throw new AccessControlException("permission denied: target user does not match current user"); - + LdapUserDAO<T> userDAO = null; LdapConnections conns = new LdapConnections(this); try @@ -405,7 +405,7 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im Subject caller = AuthenticationUtil.getCurrentSubject(); if ( !isMatch(caller, userID) ) throw new AccessControlException("permission denied: target user does not match current user"); - + LdapUserDAO<T> userDAO = null; LdapConnections conns = new LdapConnections(this); try @@ -489,7 +489,7 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im Subject caller = AuthenticationUtil.getCurrentSubject(); if ( !isMatch(caller, userID) ) throw new AccessControlException("permission denied: target user does not match current user"); - + LdapUserDAO<T> userDAO = null; LdapConnections conns = new LdapConnections(this); try @@ -523,14 +523,14 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im Subject caller = AuthenticationUtil.getCurrentSubject(); if ( !isMatch(caller, userID) ) throw new AccessControlException("permission denied: target user does not match current user"); - + LdapUserDAO<T> userDAO = null; LdapConnections conns = new LdapConnections(this); try { userDAO = new LdapUserDAO<T>(conns); User<T> user = getUser((T) userID); - + if (user != null) { // oldPassword is correct @@ -547,7 +547,7 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im { 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()) @@ -558,12 +558,12 @@ public class LdapUserPersistence<T extends Principal> extends LdapPersistence im } return false; } - + private boolean isMatch(Subject caller, Principal userID) { 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)) 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..8fe2dc7c2dda44e4787b76706f18e6bf94362b55 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 @@ -68,6 +68,24 @@ */ package ca.nrc.cadc.ac.server.web; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.security.AccessControlContext; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.Set; + +import javax.security.auth.Subject; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; + import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupNotFoundException; import ca.nrc.cadc.ac.UserNotFoundException; @@ -75,8 +93,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; @@ -84,23 +100,6 @@ import ca.nrc.cadc.uws.server.JobRunner; import ca.nrc.cadc.uws.server.JobUpdater; import ca.nrc.cadc.uws.server.SyncOutput; import ca.nrc.cadc.uws.util.JobLogInfo; -import org.apache.log4j.Logger; - -import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.security.AccessControlContext; -import java.security.AccessControlException; -import java.security.AccessController; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.Iterator; -import java.util.Set; public class ACSearchRunner implements JobRunner { @@ -221,9 +220,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/LoginServlet.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/LoginServlet.java index 9bada3806a19fc92aedc22320927669f45a5b8b2..e41f01817445947ec685ae08d934590998f29df4 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 @@ -208,6 +208,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(); diff --git a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyPasswordServlet.java b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyPasswordServlet.java index 4e68b789397db8ca67355366dc37fd537b6d55ba..90d54ebbe421db5bd8d42296e399156601eed8b2 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyPasswordServlet.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 @@ -130,8 +134,7 @@ public class ModifyPasswordServlet extends HttpServlet 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 ModifyPasswordServlet 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,61 @@ public class ModifyPasswordServlet 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()); + } } } 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 index d3d166e7ea72a890568579eb99a53047bde639e1..8d91304af9065bc4a4aacd4391908055c1ee2a74 100644 --- a/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ResetPasswordServlet.java +++ b/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ResetPasswordServlet.java @@ -68,29 +68,6 @@ */ package ca.nrc.cadc.ac.server.web; -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.util.StringUtil; - -import org.apache.log4j.Logger; - -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 java.io.IOException; import java.net.URI; import java.security.AccessControlException; @@ -99,12 +76,35 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Calendar; -import java.util.Enumeration; 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 @@ -144,7 +144,7 @@ public class ResetPasswordServlet extends HttpServlet { 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++) { @@ -164,14 +164,14 @@ public class ResetPasswordServlet extends HttpServlet 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(); @@ -210,7 +210,7 @@ public class ResetPasswordServlet extends HttpServlet return false; } - + /** * Handle a /ac GET operation. The subject provided is expected to be a privileged user. * @@ -254,7 +254,7 @@ public class ResetPasswordServlet extends HttpServlet 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 @@ -263,7 +263,7 @@ public class ResetPasswordServlet extends HttpServlet } } }); - + response.setContentType("text/plain"); response.setContentLength(token.length()); response.getWriter().write(token); @@ -287,7 +287,7 @@ public class ResetPasswordServlet extends HttpServlet throw e; } } - + throw t; } catch (UserAlreadyExistsException e) @@ -308,6 +308,18 @@ public class ResetPasswordServlet extends HttpServlet 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); @@ -359,13 +371,13 @@ public class ResetPasswordServlet extends HttpServlet { 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"); @@ -377,7 +389,7 @@ public class ResetPasswordServlet extends HttpServlet { throw new IllegalArgumentException("Missing password"); } - + return null; } }); @@ -395,7 +407,7 @@ public class ResetPasswordServlet extends HttpServlet throw e; } } - + throw t; } catch (UserNotFoundException e) 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..68ad07dacda36c2a0063ca287685c152445b84f4 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,24 @@ */ package ca.nrc.cadc.ac.server.web.groups; +import java.io.IOException; +import java.security.AccessControlException; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.List; + +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.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.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,9 +184,11 @@ 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); } 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 8888e0007b05bf59fa4dd7ba2c7c1f50e4672da2..09aaa45d453fb3f25bc00d4d3847231de3a7173d 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,6 +68,16 @@ */ 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.Principal; +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; @@ -86,17 +96,6 @@ 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 AbstractUserAction<T extends Principal> implements PrivilegedExceptionAction<Object> { private static final Logger log = Logger.getLogger(AbstractUserAction.class); @@ -193,9 +192,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); } 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/web/ModifyPasswordServletTest.java b/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/ModifyPasswordServletTest.java index 25ee26f86f4c2fcdf646811c794a4b0e14b1091a..e7c402e2dda7ec15328a1bf0cb40ff5c846e28f0 100644 --- 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 @@ -68,11 +68,13 @@ package ca.nrc.cadc.ac.server.web; -import ca.nrc.cadc.ac.server.UserPersistence; -import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.util.StringUtil; +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 org.junit.Test; +import java.security.PrivilegedExceptionAction; import javax.security.auth.Subject; import javax.servlet.ServletConfig; @@ -80,15 +82,24 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.security.PrivilegedExceptionAction; +import org.apache.log4j.Level; +import org.junit.Test; -import static org.easymock.EasyMock.*; +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 void testSubjectAndPasswords(final Subject subject, final String oldPassword, + + 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") @@ -100,27 +111,33 @@ public class ModifyPasswordServletTest 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 @@ -130,24 +147,24 @@ public class ModifyPasswordServletTest 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 { @@ -155,7 +172,7 @@ public class ModifyPasswordServletTest subject.getPrincipals().add(new HttpPrincipal("CADCtest")); testSubjectAndPasswords(subject, "", "newPass", HttpServletResponse.SC_BAD_REQUEST); } - + @Test public void testModifyPasswordWithMissingNewPassword() throws Exception { @@ -163,13 +180,13 @@ public class ModifyPasswordServletTest 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); @@ -180,7 +197,7 @@ public class ModifyPasswordServletTest final Subject subject = new Subject(); subject.getPrincipals().add(userID); - + @SuppressWarnings("serial") final ModifyPasswordServlet testSubject = new ModifyPasswordServlet() { @@ -191,33 +208,36 @@ public class ModifyPasswordServletTest 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 @@ -228,18 +248,18 @@ public class ModifyPasswordServletTest return null; } }); - + verify(mockRequest, mockResponse, mockUserPersistence); } - - + + @Test public void testModifyPasswordWithInternalServerError() throws Exception { boolean hasInternalServerError = true; testModifyPassword(hasInternalServerError); } - + @Test public void testModifyPasswordHappyPath() throws Exception {