diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java index 5cc7a94b1..61d35c43b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper.java @@ -60,30 +60,6 @@ public class PolicyHelper { return !getRequiredAuthorizationsForServlet(servletClass).isEmpty(); } - /** - * What RequestedActions does this servlet require authorization for? - */ - public static Set getRequiredAuthorizationsForServlet( - Class clazz) { - Set result = new HashSet(); - - RequiresAuthorizationFor annotation = clazz - .getAnnotation(RequiresAuthorizationFor.class); - - if (annotation != null) { - for (Class actionClass : annotation - .value()) { - if (NoAction.class != actionClass) { - RequestedAction action = instantiateAction(actionClass); - if (action != null) { - result.add(action); - } - } - } - } - return result; - } - /** * Are the actions that this servlet requires authorized for the current * user by the current policies? @@ -91,6 +67,16 @@ public class PolicyHelper { public static boolean areRequiredAuthorizationsSatisfied( HttpServletRequest req, VitroHttpServlet servlet) { Class servletClass = servlet.getClass(); + return areRequiredAuthorizationsSatisfied(req, servletClass); + } + + /** + * Are the actions that this servlet class requires authorized for the + * current user by the current policies? + */ + public static boolean areRequiredAuthorizationsSatisfied( + HttpServletRequest req, + Class servletClass) { return areRequiredAuthorizationsSatisfied(req, getRequiredAuthorizationsForServlet(servletClass)); } @@ -157,6 +143,34 @@ public class PolicyHelper { || (decision.getAuthorized() != Authorization.AUTHORIZED); } + /** + * What RequestedActions does this servlet require authorization for? + * + * Keep this private, since it reveals how the Annotation is implemented. If + * we change the Annotation to include "or" and "and", then this method + * becomes meaningless with its current return type. + */ + private static Set getRequiredAuthorizationsForServlet( + Class clazz) { + Set result = new HashSet(); + + RequiresAuthorizationFor annotation = clazz + .getAnnotation(RequiresAuthorizationFor.class); + + if (annotation != null) { + for (Class actionClass : annotation + .value()) { + if (NoAction.class != actionClass) { + RequestedAction action = instantiateAction(actionClass); + if (action != null) { + result.add(action); + } + } + } + } + return result; + } + /** * Instantiate actions from their classes. If any one of the classes cannot * be instantiated, return null. diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelperTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelperTest.java new file mode 100644 index 000000000..3cead99c1 --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelperTest.java @@ -0,0 +1,169 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.auth.policy; + +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.apache.log4j.Level; +import org.junit.Before; +import org.junit.Test; + +import stubs.javax.servlet.ServletContextStub; +import stubs.javax.servlet.http.HttpServletRequestStub; +import stubs.javax.servlet.http.HttpSessionStub; +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; +import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle; +import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper.RequiresAuthorizationFor; +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; +import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet; + +/** + * Test the basic top-level function of PolicyHelper. + */ +public class PolicyHelperTest extends AbstractTestClass { + private ServletContextStub ctx; + private HttpSessionStub session; + private HttpServletRequestStub req; + + @Before + public void setLogging() { + setLoggerLevel(ServletPolicyList.class, Level.WARN); + } + + @Before + public void setup() { + ctx = new ServletContextStub(); + + session = new HttpSessionStub(); + session.setServletContext(ctx); + + req = new HttpServletRequestStub(); + req.setSession(session); + } + + @Test + public void noAnnotation() { + createPolicy(); + assertExpectedAuthorization("no actions required", + NoAnnotationServlet.class, true); + } + + @Test + public void noRequirements() { + createPolicy(); + assertExpectedAuthorization("no actions required", + NoRequirementsServlet.class, true); + } + + @Test + public void oneRequirementFail() { + createPolicy(); + assertExpectedAuthorization("requires Action1", Action1Servlet.class, + false); + } + + @Test + public void oneRequirementSucceed() { + createPolicy(new Action1()); + assertExpectedAuthorization("requires Action1", Action1Servlet.class, + true); + } + + @Test + public void twoRequirementsFailOne() { + createPolicy(new Action1()); + assertExpectedAuthorization("requires Actions 1 and 2", + Action1Action2Servlet.class, false); + } + + @Test + public void twoRequirementsFailTwo() { + createPolicy(new Action2()); + assertExpectedAuthorization("requires Actions 1 and 2", + Action1Action2Servlet.class, false); + } + + @Test + public void twoRequirementsSucceed() { + createPolicy(new Action2(), new Action1()); + assertExpectedAuthorization("requires Actions 1 and 2", + Action1Action2Servlet.class, true); + } + + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + private void createPolicy(RequestedAction... authorizedActions) { + ServletPolicyList.addPolicy(ctx, new MySimplePolicy(authorizedActions)); + } + + private void assertExpectedAuthorization(String label, + Class servletClass, boolean expected) { + boolean actual = PolicyHelper.areRequiredAuthorizationsSatisfied(req, + servletClass); + assertEquals(label, expected, actual); + } + + // ---------------------------------------------------------------------- + // Helper Classes + // ---------------------------------------------------------------------- + + public static class Action1 extends RequestedAction { + // actions must be public, with public constructor + } + + public static class Action2 extends RequestedAction { + // actions must be public, with public constructor + } + + // no annotation + private static class NoAnnotationServlet extends VitroHttpServlet { + /* no body */ + } + + @RequiresAuthorizationFor + private static class NoRequirementsServlet extends VitroHttpServlet { + /* no body */ + } + + @RequiresAuthorizationFor(Action1.class) + private static class Action1Servlet extends VitroHttpServlet { + /* no body */ + } + + @RequiresAuthorizationFor({ Action1.class, Action2.class }) + private static class Action1Action2Servlet extends VitroHttpServlet { + /* no body */ + } + + private static class MySimplePolicy implements PolicyIface { + private final Set authorizedActions; + + public MySimplePolicy(RequestedAction... authorizedActions) { + this.authorizedActions = new HashSet( + Arrays.asList(authorizedActions)); + } + + @Override + public PolicyDecision isAuthorized(IdentifierBundle whoToAuth, + RequestedAction whatToAuth) { + for (RequestedAction authorized : authorizedActions) { + if (authorized.getClass().equals(whatToAuth.getClass())) { + return new BasicPolicyDecision(Authorization.AUTHORIZED, + "matched " + authorized.getClass().getSimpleName()); + } + + } + return new BasicPolicyDecision(Authorization.INCONCLUSIVE, "nope"); + } + + } +}