NIHVIVO-2492 Convert JSP tag to be Actions-based
This commit is contained in:
parent
8ac723b606
commit
447e9ac7ee
5 changed files with 239 additions and 52 deletions
|
@ -28,6 +28,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper.RequiresAuthori
|
|||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction;
|
||||
|
||||
/**
|
||||
|
@ -37,6 +38,25 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAct
|
|||
public class PolicyHelper {
|
||||
private static final Log log = LogFactory.getLog(PolicyHelper.class);
|
||||
|
||||
/**
|
||||
* Are the actions that this servlet requires authorized for the current
|
||||
* user by the current policies?
|
||||
*/
|
||||
public static boolean isAuthorizedForActions(HttpServletRequest req,
|
||||
Actions actions) {
|
||||
PolicyIface policy = ServletPolicyList.getPolicies(req);
|
||||
IdentifierBundle ids = RequestIdentifiers.getIdBundleForRequest(req);
|
||||
return Actions.notNull(actions).isAuthorized(policy, ids);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------
|
||||
// Obsolete ????????
|
||||
// ----------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A subclass of VitroHttpServlet may be annotated to say what actions
|
||||
* should be checked for authorization before permitting the user to view
|
||||
|
@ -73,18 +93,6 @@ public class PolicyHelper {
|
|||
Or[] or() default @Or();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this servlet require authorization?
|
||||
*/
|
||||
public static boolean isServletRestricted(HttpServlet servlet) {
|
||||
Class<? extends HttpServlet> servletClass = servlet.getClass();
|
||||
try {
|
||||
return !ActionClauses.forServletClass(servletClass).isEmpty();
|
||||
} catch (PolicyHelperException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Are the actions that this servlet requires authorized for the current
|
||||
* user by the current policies?
|
||||
|
@ -108,20 +116,6 @@ public class PolicyHelper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Are these action classes authorized for the current user by the current
|
||||
* policies?
|
||||
*/
|
||||
public static boolean isAuthorizedForActions(HttpServletRequest req,
|
||||
Collection<Class<? extends RequestedAction>> actionClasses) {
|
||||
try {
|
||||
return isAuthorizedForActionClauses(req, new ActionClauses(
|
||||
actionClasses));
|
||||
} catch (PolicyHelperException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action class authorized for the current user by the current
|
||||
* policies?
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.auth.requestedAction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction;
|
||||
|
||||
/**
|
||||
* An immutable list of OR and AND relationships for the required
|
||||
* authorizations. A group of AND relationships is a "clause", and the list of
|
||||
* clauses are in an OR relationship.
|
||||
*
|
||||
* Authorization is successful if ALL of the actions in ANY of the clauses are
|
||||
* authorized, or if there are NO clauses.
|
||||
*/
|
||||
public class Actions {
|
||||
private static final Log log = LogFactory.getLog(Actions.class);
|
||||
|
||||
public static Actions notNull(Actions actions) {
|
||||
return (actions == null) ? new Actions() : actions;
|
||||
}
|
||||
|
||||
private final List<Set<RequestedAction>> clauseList;
|
||||
|
||||
public Actions(RequestedAction... actions) {
|
||||
this(Arrays.asList(actions));
|
||||
}
|
||||
|
||||
public Actions(Collection<RequestedAction> actions) {
|
||||
this(Collections.<Set<RequestedAction>> emptyList(), actions);
|
||||
}
|
||||
|
||||
private Actions(List<Set<RequestedAction>> oldList,
|
||||
Collection<RequestedAction> newActions) {
|
||||
List<Set<RequestedAction>> newList = new ArrayList<Set<RequestedAction>>();
|
||||
newList.addAll(oldList);
|
||||
|
||||
Set<RequestedAction> newActionSet = new HashSet<RequestedAction>(
|
||||
newActions);
|
||||
if (!newActionSet.isEmpty()) {
|
||||
newList.add(Collections.unmodifiableSet(newActionSet));
|
||||
}
|
||||
this.clauseList = Collections.unmodifiableList(newList);
|
||||
}
|
||||
|
||||
public Actions or(RequestedAction... newActions) {
|
||||
return or(Arrays.asList(newActions));
|
||||
}
|
||||
|
||||
public Actions or(Collection<RequestedAction> newActions) {
|
||||
return new Actions(this.clauseList, newActions);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
for (Set<RequestedAction> clause : clauseList) {
|
||||
if (!clause.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** No clauses means everything is authorized */
|
||||
public boolean isAuthorized(PolicyIface policy, IdentifierBundle ids) {
|
||||
return clauseList.isEmpty() || isAuthorizedForClauseList(policy, ids);
|
||||
}
|
||||
|
||||
/** Any entire clause is good enough. */
|
||||
private boolean isAuthorizedForClauseList(PolicyIface policy,
|
||||
IdentifierBundle ids) {
|
||||
for (Set<RequestedAction> clause : clauseList) {
|
||||
if (isAuthorizedForClause(policy, ids, clause)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** All actions in a clause must be authorized. */
|
||||
private static boolean isAuthorizedForClause(PolicyIface policy,
|
||||
IdentifierBundle ids, Set<RequestedAction> clause) {
|
||||
for (RequestedAction action : clause) {
|
||||
if (!isAuthorizedForAction(policy, ids, action)) {
|
||||
log.debug("not authorized");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Is this action authorized? */
|
||||
private static boolean isAuthorizedForAction(PolicyIface policy,
|
||||
IdentifierBundle ids, RequestedAction action) {
|
||||
PolicyDecision decision = policy.isAuthorized(ids, action);
|
||||
log.debug("decision for '" + action.getClass().getName() + "' was: "
|
||||
+ decision);
|
||||
return (decision != null)
|
||||
&& (decision.getAuthorized() == Authorization.AUTHORIZED);
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
|
||||
import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.LogoutRedirector;
|
||||
|
||||
|
@ -40,15 +41,9 @@ public class VitroHttpServlet extends HttpServlet {
|
|||
public final static String HTML_MIMETYPE = "text/html";
|
||||
|
||||
public final static String RDFXML_MIMETYPE = "application/rdf+xml";
|
||||
public final static String N3_MIMETYPE = "text/n3"; // unofficial and
|
||||
// unregistered
|
||||
public final static String TTL_MIMETYPE = "text/turtle"; // unofficial and
|
||||
// unregistered
|
||||
public final static String N3_MIMETYPE = "text/n3"; // unofficial and unregistered
|
||||
public final static String TTL_MIMETYPE = "text/turtle"; // unofficial and unregistered
|
||||
|
||||
/**
|
||||
* Check that any required authorizations are satisfied before processing
|
||||
* the request.
|
||||
*/
|
||||
@Override
|
||||
public final void service(ServletRequest req, ServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
|
@ -61,22 +56,6 @@ public class VitroHttpServlet extends HttpServlet {
|
|||
dumpRequestHeaders(hreq);
|
||||
}
|
||||
|
||||
// Record restricted pages so we won't return to them on logout
|
||||
if (PolicyHelper.isServletRestricted(this)) {
|
||||
LogoutRedirector.recordRestrictedPageUri(hreq);
|
||||
}
|
||||
|
||||
// If the user isn't authorized for this servlet, don't show it.
|
||||
if (!PolicyHelper.isAuthorizedForServlet(hreq, this)) {
|
||||
if (LoginStatusBean.getBean(hreq).isLoggedIn()) {
|
||||
redirectToInsufficientAuthorizationPage(hreq, hresp);
|
||||
return;
|
||||
} else {
|
||||
redirectToLoginPage(hreq, hresp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check to see if VitroRequestPrep filter was run
|
||||
if (hreq.getAttribute("appBean") == null
|
||||
|| hreq.getAttribute("webappDaoFactory") == null) {
|
||||
|
@ -114,6 +93,36 @@ public class VitroHttpServlet extends HttpServlet {
|
|||
doGet(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't display a page that the user isn't authorized to see.
|
||||
*
|
||||
* @param actions
|
||||
* the RequestedActions that need to be authorized.
|
||||
*/
|
||||
protected boolean isAuthorizedToDisplayPage(HttpServletRequest request,
|
||||
HttpServletResponse response, Actions actions) {
|
||||
// Record restricted pages so we won't return to them on logout
|
||||
LogoutRedirector.recordRestrictedPageUri(request);
|
||||
|
||||
if (PolicyHelper.isAuthorizedForActions(request, actions)) {
|
||||
log.debug("Servlet '" + this.getClass().getSimpleName()
|
||||
+ "' is authorized for actions: " + actions);
|
||||
return true;
|
||||
}
|
||||
|
||||
log.debug("Servlet '" + this.getClass().getSimpleName()
|
||||
+ "' is not authorized for actions: " + actions);
|
||||
|
||||
LoginStatusBean statusBean = LoginStatusBean.getBean(request);
|
||||
if (statusBean.isLoggedIn()) {
|
||||
redirectToInsufficientAuthorizationPage(request, response);
|
||||
return false;
|
||||
} else {
|
||||
redirectToLoginPage(request, response);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// static utility methods for all Vitro servlets
|
||||
// ----------------------------------------------------------------------
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
|
||||
import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
||||
|
||||
|
@ -60,7 +61,8 @@ public class RequiresAuthorizationFor extends BodyTagSupport {
|
|||
if (classes == null) {
|
||||
return false;
|
||||
}
|
||||
return PolicyHelper.isAuthorizedForActions(getRequest(), classes);
|
||||
Set<RequestedAction> actionSet = getInstancesFromClasses(classes);
|
||||
return PolicyHelper.isAuthorizedForActions(getRequest(), new Actions(actionSet));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,7 +136,7 @@ public class RequiresAuthorizationFor extends BodyTagSupport {
|
|||
return SKIP_PAGE;
|
||||
}
|
||||
|
||||
private int redirectToLoginPage() throws JspException {
|
||||
private int redirectToLoginPage() {
|
||||
VitroHttpServlet.redirectToLoginPage(getRequest(), getResponse());
|
||||
return SKIP_PAGE;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper.RequiresAuthori
|
|||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
||||
|
||||
|
@ -49,6 +50,73 @@ public class PolicyHelperTest extends AbstractTestClass {
|
|||
req.setSession(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizedForActionsNull() {
|
||||
createPolicy();
|
||||
assertEquals("null actions", true,
|
||||
PolicyHelper.isAuthorizedForActions(req, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizedForActionsEmpty() {
|
||||
createPolicy();
|
||||
assertEquals("empty actions", true,
|
||||
PolicyHelper.isAuthorizedForActions(req, new Actions()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizedForActionsOneClausePass() {
|
||||
createPolicy(new Action1(), new Action2());
|
||||
assertEquals("one clause pass", true,
|
||||
PolicyHelper.isAuthorizedForActions(req, new Actions(
|
||||
new Action1(), new Action2())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizedForActionsOneClauseFail() {
|
||||
createPolicy(new Action2());
|
||||
assertEquals("one clause fail", false,
|
||||
PolicyHelper.isAuthorizedForActions(req, new Actions(
|
||||
new Action1(), new Action2())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizedForActionsMultipleClausesPass() {
|
||||
createPolicy(new Action3());
|
||||
assertEquals("multiple clauses pass", true,
|
||||
PolicyHelper.isAuthorizedForActions(req, new Actions(
|
||||
new Action1(), new Action2()).or(new Action3())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizedForActionsMultipleClausesFail() {
|
||||
createPolicy(new Action1());
|
||||
assertEquals("multiple clauses fail", false,
|
||||
PolicyHelper.isAuthorizedForActions(req, new Actions(
|
||||
new Action1(), new Action2()).or(new Action3())));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* actions is null,
|
||||
* actions is empty
|
||||
* actions has one clause with multiple actions
|
||||
* all pass
|
||||
* some pass
|
||||
* action has multiple clauses
|
||||
* one passes
|
||||
* none pass (but partial passes)
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------
|
||||
// Obsolete???
|
||||
// ----------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@Test
|
||||
public void noAnnotation() {
|
||||
createPolicy();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue