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.Authorization;
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
|
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.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.auth.requestedAction.ifaces.RequestedAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,6 +38,25 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAct
|
||||||
public class PolicyHelper {
|
public class PolicyHelper {
|
||||||
private static final Log log = LogFactory.getLog(PolicyHelper.class);
|
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
|
* A subclass of VitroHttpServlet may be annotated to say what actions
|
||||||
* should be checked for authorization before permitting the user to view
|
* should be checked for authorization before permitting the user to view
|
||||||
|
@ -73,18 +93,6 @@ public class PolicyHelper {
|
||||||
Or[] or() default @Or();
|
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
|
* Are the actions that this servlet requires authorized for the current
|
||||||
* user by the current policies?
|
* 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
|
* Is this action class authorized for the current user by the current
|
||||||
* policies?
|
* 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.vedit.beans.LoginStatusBean;
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
|
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.beans.DisplayMessage;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.LogoutRedirector;
|
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 HTML_MIMETYPE = "text/html";
|
||||||
|
|
||||||
public final static String RDFXML_MIMETYPE = "application/rdf+xml";
|
public final static String RDFXML_MIMETYPE = "application/rdf+xml";
|
||||||
public final static String N3_MIMETYPE = "text/n3"; // unofficial and
|
public final static String N3_MIMETYPE = "text/n3"; // unofficial and unregistered
|
||||||
// unregistered
|
public final static String TTL_MIMETYPE = "text/turtle"; // 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
|
@Override
|
||||||
public final void service(ServletRequest req, ServletResponse resp)
|
public final void service(ServletRequest req, ServletResponse resp)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
@ -61,22 +56,6 @@ public class VitroHttpServlet extends HttpServlet {
|
||||||
dumpRequestHeaders(hreq);
|
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
|
// check to see if VitroRequestPrep filter was run
|
||||||
if (hreq.getAttribute("appBean") == null
|
if (hreq.getAttribute("appBean") == null
|
||||||
|| hreq.getAttribute("webappDaoFactory") == null) {
|
|| hreq.getAttribute("webappDaoFactory") == null) {
|
||||||
|
@ -114,6 +93,36 @@ public class VitroHttpServlet extends HttpServlet {
|
||||||
doGet(request, response);
|
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
|
// 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.vedit.beans.LoginStatusBean;
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
|
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.auth.requestedAction.ifaces.RequestedAction;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
||||||
|
|
||||||
|
@ -60,7 +61,8 @@ public class RequiresAuthorizationFor extends BodyTagSupport {
|
||||||
if (classes == null) {
|
if (classes == null) {
|
||||||
return false;
|
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;
|
return SKIP_PAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int redirectToLoginPage() throws JspException {
|
private int redirectToLoginPage() {
|
||||||
VitroHttpServlet.redirectToLoginPage(getRequest(), getResponse());
|
VitroHttpServlet.redirectToLoginPage(getRequest(), getResponse());
|
||||||
return SKIP_PAGE;
|
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.Authorization;
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
|
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.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.auth.requestedAction.ifaces.RequestedAction;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
||||||
|
|
||||||
|
@ -49,6 +50,73 @@ public class PolicyHelperTest extends AbstractTestClass {
|
||||||
req.setSession(session);
|
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
|
@Test
|
||||||
public void noAnnotation() {
|
public void noAnnotation() {
|
||||||
createPolicy();
|
createPolicy();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue