diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/RequestValidator.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/RequestValidator.java index 34ac1751a460bda63ac222e98acedbf378ea7b57..aed7d70912d12d8fa45962f859b453c0e6177864 100644 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/RequestValidator.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/RequestValidator.java @@ -68,12 +68,14 @@ */ package ca.nrc.cadc.ac.server; +import java.util.List; + +import org.apache.log4j.Logger; + import ca.nrc.cadc.ac.IdentityType; import ca.nrc.cadc.ac.Role; import ca.nrc.cadc.uws.Parameter; import ca.nrc.cadc.uws.ParameterUtil; -import java.util.List; -import org.apache.log4j.Logger; /** * Request Validator. This class extracts and validates the ID, TYPE, ROLE @@ -105,7 +107,7 @@ public class RequestValidator if (paramList == null || paramList.isEmpty()) { throw new IllegalArgumentException( - "Missing required parameters: ID and TYPE"); + "Missing required parameters: ID and IDTYPE"); } // ID @@ -118,12 +120,12 @@ public class RequestValidator this.userID = param.trim(); log.debug("ID: " + userID); - // TYPE - param = ParameterUtil.findParameterValue("TYPE", paramList); + // IDTYPE + param = ParameterUtil.findParameterValue("IDTYPE", paramList); if (param == null || param.trim().isEmpty()) { throw new IllegalArgumentException( - "TYPE parameter required but not found"); + "IDTYPE parameter required but not found"); } this.idType = IdentityType.toValue(param); log.debug("TYPE: " + idType); diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java index 11a7f00b07f5c951d20fc9a6ddf17cfaa4b997a9..287f9d283ad1eb6714cb695e648b76e0b9e7bb3d 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java @@ -212,7 +212,7 @@ public abstract class LdapDAO { throw new AccessControlException("Invalid credentials " + msg); } - else if (code == ResultCode.SUCCESS) + else if ((code == ResultCode.SUCCESS) || (code == ResultCode.NO_SUCH_OBJECT) ) { // all good. nothing to do } diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java index f0a205a46c77ca5ebf4a39a0503b140dd8241952..3223b21b7053126f0e58b7e646ee00b00e16eec2 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java @@ -72,6 +72,7 @@ import java.security.AccessControlException; import java.security.Principal; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -104,7 +105,6 @@ import com.unboundid.ldap.sdk.SearchResult; import com.unboundid.ldap.sdk.SearchResultEntry; import com.unboundid.ldap.sdk.SearchScope; import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl; -import java.util.HashSet; public class LdapGroupDAO<T extends Principal> extends LdapDAO { @@ -345,7 +345,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO { String [] attributes = new String[] {"entrydn", "cn", "description", "owner", "uniquemember", - "modifytimestamp"}; + "modifytimestamp", "nsaccountlock"}; return getGroup(groupDN, groupID, withMembers, attributes); } @@ -366,10 +366,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO { try { - Filter filter = Filter.createANDFilter( - Filter.createEqualityFilter("cn", groupID), - Filter.createNOTFilter( - Filter.createEqualityFilter("nsaccountlock", "TRUE"))); + Filter filter = Filter.createEqualityFilter("cn", groupID); SearchRequest searchRequest = new SearchRequest(groupDN.toNormalizedString(), @@ -386,11 +383,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } catch (LDAPSearchException e) { - if (e.getResultCode() == ResultCode.AUTHORIZATION_DENIED) - { - throw new AccessControlException("Unauthorized to access group " + groupID); - } - else if (e.getResultCode() == ResultCode.NO_SUCH_OBJECT) + if (e.getResultCode() == ResultCode.NO_SUCH_OBJECT) { String msg = "Group not found " + groupID; logger.debug(msg); @@ -398,23 +391,34 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } else { - throw new RuntimeException("Unknown LDAP exception: " + e.getResultCode()); + LdapDAO.checkLdapResult(e.getResultCode(), e.getMessage()); } } if (searchResult.getEntryCount() == 0) { - // deleted groups? - String msg = "Group not found " + groupID; + LdapDAO.checkLdapResult(searchResult.getResultCode(), null); + //access denied + String msg = "Not authorized to access " + groupID; logger.debug(msg); - throw new GroupNotFoundException(groupID); + throw new AccessControlException(groupID); } if (searchResult.getEntryCount() >1) { throw new RuntimeException("BUG: multiple results when retrieving group " + groupID); } + SearchResultEntry searchEntry = searchResult.getSearchEntries().get(0); + + if (searchEntry.getAttribute("nsaccountlock") != null) + { + // deleted group + String msg = "Group not found " + groupID; + logger.debug(msg); + throw new GroupNotFoundException(groupID); + } + String groupCN = searchEntry.getAttributeValue("cn"); DN groupOwner = searchEntry.getAttributeValueAsDN("owner"); diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java index aabfca8a2d92705cc34fd980fa6af7975549521d..0418acda1fa64b3f0b36e42ea8fa191ed75f76ed 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java @@ -68,38 +68,30 @@ */ package ca.nrc.cadc.ac.server.web; +import java.security.AccessControlException; +import java.security.Principal; +import java.util.Collection; +import java.util.Date; + +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.GroupsWriter; -import ca.nrc.cadc.ac.IdentityType; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.ac.server.GroupPersistence; import ca.nrc.cadc.ac.server.PluginFactory; import ca.nrc.cadc.ac.server.RequestValidator; -import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.auth.AuthenticationUtil; -import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.auth.NumericPrincipal; -import ca.nrc.cadc.auth.OpenIdPrincipal; import ca.nrc.cadc.net.TransientException; -import ca.nrc.cadc.uws.ErrorSummary; -import ca.nrc.cadc.uws.ErrorType; import ca.nrc.cadc.uws.ExecutionPhase; import ca.nrc.cadc.uws.Job; -import ca.nrc.cadc.uws.server.JobNotFoundException; -import ca.nrc.cadc.uws.server.JobPersistenceException; 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 java.io.IOException; -import java.security.AccessControlException; -import java.security.Principal; -import java.util.Collection; -import java.util.Date; -import javax.security.auth.x500.X500Principal; -import javax.servlet.http.HttpServletResponse; -import org.apache.log4j.Logger; public class ACSearchRunner implements JobRunner { @@ -151,6 +143,15 @@ public class ACSearchRunner implements JobRunner @SuppressWarnings("unchecked") private void search() { + + // Note: This search runner is customized to run with + // InMemoryJobPersistence, and synchronous POST requests are + // dealt with immediately, rather than returning results via + // a redirect. + // Jobs in this runner are never updated after execution begins + // in case the in-memory job has gone away. Error reporting + // is done directly through the response on both POST and GET + try { ExecutionPhase ep = @@ -158,11 +159,7 @@ public class ACSearchRunner implements JobRunner ExecutionPhase.EXECUTING, new Date()); if ( !ExecutionPhase.EXECUTING.equals(ep) ) { - String message = job.getID() + - ": QUEUED -> EXECUTING [FAILED] -- DONE"; - logInfo.setSuccess(false); - logInfo.setMessage(message); - return; + throw new IllegalStateException("QUEUED -> EXECUTING [FAILED]"); } log.debug(job.getID() + ": QUEUED -> EXECUTING [OK]"); @@ -181,29 +178,29 @@ public class ACSearchRunner implements JobRunner GroupsWriter.write(groups, syncOut.getOutputStream()); // Mark the Job as completed. - jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, - ExecutionPhase.COMPLETED, new Date()); +// jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, +// ExecutionPhase.COMPLETED, new Date()); } catch (TransientException t) { logInfo.setSuccess(false); logInfo.setMessage(t.getMessage()); - log.debug("FAIL", t); + log.error("FAIL", t); - syncOut.setResponseCode(400); + syncOut.setResponseCode(503); - ErrorSummary errorSummary = - new ErrorSummary(t.getMessage(), ErrorType.FATAL); - try - { - jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, - ExecutionPhase.ERROR, errorSummary, - new Date()); - } - catch(Throwable oops) - { - log.debug("failed to set final error status after " + t, oops); - } +// ErrorSummary errorSummary = +// new ErrorSummary(t.getMessage(), ErrorType.FATAL); +// try +// { +// jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, +// ExecutionPhase.ERROR, errorSummary, +// new Date()); +// } +// catch(Throwable oops) +// { +// log.debug("failed to set final error status after " + t, oops); +// } } catch (UserNotFoundException t) { @@ -213,18 +210,18 @@ public class ACSearchRunner implements JobRunner syncOut.setResponseCode(404); - ErrorSummary errorSummary = - new ErrorSummary(t.getMessage(), ErrorType.FATAL); - try - { - jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, - ExecutionPhase.ERROR, errorSummary, - new Date()); - } - catch(Throwable oops) - { - log.debug("failed to set final error status after " + t, oops); - } +// ErrorSummary errorSummary = +// new ErrorSummary(t.getMessage(), ErrorType.FATAL); +// try +// { +// jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, +// ExecutionPhase.ERROR, errorSummary, +// new Date()); +// } +// catch(Throwable oops) +// { +// log.debug("failed to set final error status after " + t, oops); +// } } catch (GroupNotFoundException t) { @@ -234,18 +231,18 @@ public class ACSearchRunner implements JobRunner syncOut.setResponseCode(404); - ErrorSummary errorSummary = - new ErrorSummary(t.getMessage(), ErrorType.FATAL); - try - { - jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, - ExecutionPhase.ERROR, errorSummary, - new Date()); - } - catch(Throwable oops) - { - log.debug("failed to set final error status after " + t, oops); - } +// ErrorSummary errorSummary = +// new ErrorSummary(t.getMessage(), ErrorType.FATAL); +// try +// { +// jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, +// ExecutionPhase.ERROR, errorSummary, +// new Date()); +// } +// catch(Throwable oops) +// { +// log.debug("failed to set final error status after " + t, oops); +// } } catch (AccessControlException t) { @@ -255,39 +252,39 @@ public class ACSearchRunner implements JobRunner syncOut.setResponseCode(401); - ErrorSummary errorSummary = - new ErrorSummary(t.getMessage(), ErrorType.FATAL); - try - { - jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, - ExecutionPhase.ERROR, errorSummary, - new Date()); - } - catch(Throwable oops) - { - log.debug("failed to set final error status after " + t, oops); - } +// ErrorSummary errorSummary = +// new ErrorSummary(t.getMessage(), ErrorType.FATAL); +// try +// { +// jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, +// ExecutionPhase.ERROR, errorSummary, +// new Date()); +// } +// catch(Throwable oops) +// { +// log.debug("failed to set final error status after " + t, oops); +// } } catch (Throwable t) { logInfo.setSuccess(false); logInfo.setMessage(t.getMessage()); - log.debug("FAIL", t); + log.error("FAIL", t); - syncOut.setResponseCode(400); + syncOut.setResponseCode(500); - ErrorSummary errorSummary = - new ErrorSummary(t.getMessage(), ErrorType.FATAL); - try - { - jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, - ExecutionPhase.ERROR, errorSummary, - new Date()); - } - catch(Throwable oops) - { - log.debug("failed to set final error status after " + t, oops); - } +// ErrorSummary errorSummary = +// new ErrorSummary(t.getMessage(), ErrorType.FATAL); +// try +// { +// jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, +// ExecutionPhase.ERROR, errorSummary, +// new Date()); +// } +// catch(Throwable oops) +// { +// log.debug("failed to set final error status after " + t, oops); +// } } } diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java index 276d5b6a9b7e479a19e9a6e2e6f08e35fe5feca0..7914b36762bd6bc64ff33594991fddfb3b73971d 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java @@ -557,8 +557,29 @@ public class LdapGroupDAOTest Subject.doAs(daoTestUser1Subject, new PrivilegedExceptionAction<Object>() { public Object run() throws Exception - { - getGroupDAO().deleteGroup(groupID); + { + try + { + getGroupDAO().getGroup(groupID); + //fail("getGroup with anonymous access should throw " + + // "AccessControlException"); + } + catch (AccessControlException ignore) {} + return null; + } + }); + + Subject.doAs(daoTestUser2Subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + getGroupDAO().getGroup(groupID); + fail("getGroup with anonymous access should throw " + + "AccessControlException"); + } + catch (AccessControlException ignore) {} return null; } }); @@ -729,10 +750,10 @@ public class LdapGroupDAOTest Group group = getGroupDAO().getGroup(groupID); assertTrue(group == null); - fail("searchGroups with unknown user should throw " + - "GroupNotFoundException"); + fail("searchGroups with un-authorized user should throw " + + "AccessControlException"); } - catch (GroupNotFoundException ignore) + catch (AccessControlException ignore) { } diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java index 4494ff0ac9c22c8f789e6e275cf49901a4443e87..00af73879e6dbdad4170573724ed246a9eb6575e 100755 --- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java +++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java @@ -86,6 +86,7 @@ import java.util.Map; import java.util.Set; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSocketFactory; import javax.security.auth.Subject; @@ -380,14 +381,24 @@ public class GMSClient ((HttpsURLConnection) conn) .setSSLSocketFactory(getSSLSocketFactory()); } - int responseCode = conn.getResponseCode(); + int responseCode = -1; + try + { + responseCode = conn.getResponseCode(); + } + catch(SSLHandshakeException e) + { + throw new AccessControlException(e.getMessage()); + } + if (responseCode != 200) { String errMessage = NetUtil.getErrorBody(conn); log.debug("deleteGroup response " + responseCode + ": " + errMessage); - if ((responseCode == 401) || (responseCode == 403)) + if ((responseCode == 401) || (responseCode == 403) || + (responseCode == -1)) { throw new AccessControlException(errMessage); } @@ -688,7 +699,7 @@ public class GMSClient searchGroupURL.append("/search?"); searchGroupURL.append("ID=" + URLEncoder.encode(id, "UTF-8")); - searchGroupURL.append("&TYPE=" + URLEncoder.encode(idType, "UTF-8")); + searchGroupURL.append("&IDTYPE=" + URLEncoder.encode(idType, "UTF-8")); searchGroupURL.append("&ROLE=" + URLEncoder.encode(roleString, "UTF-8")); log.debug("getMemberships request to " + searchGroupURL.toString()); @@ -801,7 +812,7 @@ public class GMSClient searchGroupURL.append("/search?"); searchGroupURL.append("ID=" + URLEncoder.encode(id, "UTF-8")); - searchGroupURL.append("&TYPE=" + URLEncoder.encode(idType, "UTF-8")); + searchGroupURL.append("&IDTYPE=" + URLEncoder.encode(idType, "UTF-8")); searchGroupURL.append("&ROLE=" + URLEncoder.encode(roleString, "UTF-8")); searchGroupURL.append("&GROUPID=" + URLEncoder.encode(groupName, "UTF-8"));