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 d875dbedc..d14500cff 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 @@ -7,11 +7,22 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.rdf.model.StmtIterator; + import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle; import edu.cornell.mannlib.vitro.webapp.auth.identifier.RequestIdentifiers; 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.propstmt.AddDataPropStmt; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AddObjectPropStmt; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropDataPropStmt; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.DropObjectPropStmt; /** * A collection of static methods to help determine whether requested actions @@ -28,7 +39,7 @@ public class PolicyHelper { RequestedAction... actions) { return isAuthorizedForActions(req, new Actions(actions)); } - + /** * Are these actions authorized for the current user by the current * policies? @@ -40,6 +51,109 @@ public class PolicyHelper { return Actions.notNull(actions).isAuthorized(policy, ids); } + /** + * Do the current policies authorize the current user to add all of the + * statements in this model? + */ + public static boolean isAuthorizedToAdd(HttpServletRequest req, Model model) { + if ((req == null) || (model == null)) { + return false; + } + + StmtIterator stmts = model.listStatements(); + try { + while (stmts.hasNext()) { + if (!isAuthorizedToAdd(req, stmts.next())) { + return false; + } + } + return true; + } finally { + stmts.close(); + } + } + + /** + * Do the current policies authorize the current user to add this statement? + * + * The statement is expected to be fully-populated, with no null fields. + */ + public static boolean isAuthorizedToAdd(HttpServletRequest req, + Statement stmt) { + if ((req == null) || (stmt == null)) { + return false; + } + + Resource subject = stmt.getSubject(); + Property predicate = stmt.getPredicate(); + RDFNode objectNode = stmt.getObject(); + if ((subject == null) || (predicate == null) || (objectNode == null)) { + return false; + } + + RequestedAction action; + if (objectNode.isResource()) { + action = new AddObjectPropStmt(subject.getURI(), + predicate.getURI(), objectNode.asResource().getURI()); + } else { + action = new AddDataPropStmt(subject.getURI(), predicate.getURI(), + objectNode.asLiteral()); + } + return isAuthorizedForActions(req, action); + } + + /** + * Do the current policies authorize the current user to drop all of the + * statements in this model? + */ + public static boolean isAuthorizedToDrop(HttpServletRequest req, Model model) { + if ((req == null) || (model == null)) { + return false; + } + + StmtIterator stmts = model.listStatements(); + try { + while (stmts.hasNext()) { + if (!isAuthorizedToDrop(req, stmts.next())) { + return false; + } + } + return true; + } finally { + stmts.close(); + } + } + + /** + * Do the current policies authorize the current user to drop this + * statement? + * + * The statement is expected to be fully-populated, with no null fields. + */ + public static boolean isAuthorizedToDrop(HttpServletRequest req, + Statement stmt) { + if ((req == null) || (stmt == null)) { + return false; + } + + Resource subject = stmt.getSubject(); + Property predicate = stmt.getPredicate(); + RDFNode objectNode = stmt.getObject(); + if ((subject == null) || (predicate == null) || (objectNode == null)) { + return false; + } + + RequestedAction action; + if (objectNode.isResource()) { + action = new DropObjectPropStmt(subject.getURI(), + predicate.getURI(), objectNode.asResource().getURI()); + } else { + action = new DropDataPropStmt(subject.getURI(), predicate.getURI(), + objectNode.asLiteral()); + } + return isAuthorizedForActions(req, action); + } + /** * No need to instantiate this helper class - all methods are static. */ diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelperTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper_ActionsTest.java similarity index 90% rename from webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelperTest.java rename to webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper_ActionsTest.java index 0d2cf12fe..d76433311 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelperTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper_ActionsTest.java @@ -24,9 +24,9 @@ import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction; /** - * Test the basic top-level function of PolicyHelper. + * Test the function of PolicyHelper in authorizing simple actions. */ -public class PolicyHelperTest extends AbstractTestClass { +public class PolicyHelper_ActionsTest extends AbstractTestClass { private ServletContextStub ctx; private HttpSessionStub session; private HttpServletRequestStub req; @@ -47,6 +47,10 @@ public class PolicyHelperTest extends AbstractTestClass { req.setSession(session); } + // ---------------------------------------------------------------------- + // Action-level tests + // ---------------------------------------------------------------------- + @Test public void authorizedForActionsNull() { createPolicy(); diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper_StatementsTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper_StatementsTest.java new file mode 100644 index 000000000..86da9b457 --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/auth/policy/PolicyHelper_StatementsTest.java @@ -0,0 +1,279 @@ +/* $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.assertEquals; + +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 com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.Statement; + +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; +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; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AbstractDataPropertyAction; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AbstractObjectPropertyAction; + +/** + * Test the function of PolicyHelper in authorizing statements and models. + */ +public class PolicyHelper_StatementsTest extends AbstractTestClass { + private static final String APPROVED_SUBJECT_URI = "test://approvedSubjectUri"; + private static final String APPROVED_PREDICATE_URI = "test://approvedPredicateUri"; + private static final String UNAPPROVED_PREDICATE_URI = "test://bogusPredicateUri"; + private static final String APPROVED_OBJECT_URI = "test://approvedObjectUri"; + + private ServletContextStub ctx; + private HttpSessionStub session; + private HttpServletRequestStub req; + + @Before + public void setup() { + ctx = new ServletContextStub(); + + session = new HttpSessionStub(); + session.setServletContext(ctx); + + req = new HttpServletRequestStub(); + req.setSession(session); + + setLoggerLevel(ServletPolicyList.class, Level.WARN); + ServletPolicyList.addPolicy(ctx, new MySimplePolicy()); + } + + // ---------------------------------------------------------------------- + // Statement-level tests. + // ---------------------------------------------------------------------- + + @Test + public void addNullStatement() { + assertEquals("null statement", false, + PolicyHelper.isAuthorizedToAdd(req, (Statement) null)); + } + + @Test + public void addStatementWithNullRequest() { + Statement stmt = dataStatement(APPROVED_SUBJECT_URI, + APPROVED_PREDICATE_URI); + assertEquals("null request", false, + PolicyHelper.isAuthorizedToAdd(null, stmt)); + } + + @Test + public void addAuthorizedStatement() { + Statement stmt = dataStatement(APPROVED_SUBJECT_URI, + APPROVED_PREDICATE_URI); + assertEquals("authorized", true, + PolicyHelper.isAuthorizedToAdd(req, stmt)); + } + + @Test + public void addUnauthorizedStatement() { + Statement stmt = dataStatement(APPROVED_SUBJECT_URI, + UNAPPROVED_PREDICATE_URI); + assertEquals("not authorized", false, + PolicyHelper.isAuthorizedToAdd(req, stmt)); + } + + @Test + public void dropNullStatement() { + assertEquals("null statement", false, + PolicyHelper.isAuthorizedToDrop(req, (Statement) null)); + } + + @Test + public void dropStatementWithNullRequest() { + Statement stmt = dataStatement(APPROVED_SUBJECT_URI, + APPROVED_PREDICATE_URI); + assertEquals("null request", false, + PolicyHelper.isAuthorizedToDrop(null, stmt)); + } + + @Test + public void dropAuthorizedStatement() { + Statement stmt = dataStatement(APPROVED_SUBJECT_URI, + APPROVED_PREDICATE_URI); + assertEquals("authorized", true, + PolicyHelper.isAuthorizedToDrop(req, stmt)); + } + + @Test + public void dropUnauthorizedStatement() { + Statement stmt = dataStatement(APPROVED_SUBJECT_URI, + UNAPPROVED_PREDICATE_URI); + assertEquals("not authorized", false, + PolicyHelper.isAuthorizedToDrop(req, stmt)); + } + + // ---------------------------------------------------------------------- + // Model-level tests + // ---------------------------------------------------------------------- + + @Test + public void addNullModel() { + assertEquals("null statement", false, + PolicyHelper.isAuthorizedToAdd(req, (Model) null)); + } + + @Test + public void addModelWithNullRequest() { + assertEquals("empty model", false, + PolicyHelper.isAuthorizedToAdd(null, model())); + } + + @Test + public void addEmptyModel() { + assertEquals("empty model", true, + PolicyHelper.isAuthorizedToAdd(req, model())); + } + + @Test + public void addAuthorizedModel() { + Model model = model( + dataStatement(APPROVED_SUBJECT_URI, APPROVED_PREDICATE_URI), + objectStatement(APPROVED_SUBJECT_URI, APPROVED_PREDICATE_URI, + APPROVED_OBJECT_URI)); + assertEquals("authorized model", true, + PolicyHelper.isAuthorizedToAdd(req, model)); + } + + @Test + public void addUnauthorizedModel() { + Model model = model( + dataStatement(APPROVED_SUBJECT_URI, APPROVED_PREDICATE_URI), + objectStatement(APPROVED_SUBJECT_URI, UNAPPROVED_PREDICATE_URI, + APPROVED_OBJECT_URI)); + assertEquals("unauthorized model", false, + PolicyHelper.isAuthorizedToAdd(req, model)); + } + + @Test + public void dropNullModel() { + assertEquals("null statement", false, + PolicyHelper.isAuthorizedToDrop(req, (Model) null)); + } + + @Test + public void dropModelWithNullRequest() { + assertEquals("empty model", false, + PolicyHelper.isAuthorizedToDrop(null, model())); + } + + @Test + public void dropEmptyModel() { + assertEquals("empty model", true, + PolicyHelper.isAuthorizedToDrop(req, model())); + } + + @Test + public void dropAuthorizedModel() { + Model model = model( + dataStatement(APPROVED_SUBJECT_URI, APPROVED_PREDICATE_URI), + objectStatement(APPROVED_SUBJECT_URI, APPROVED_PREDICATE_URI, + APPROVED_OBJECT_URI)); + assertEquals("authorized model", true, + PolicyHelper.isAuthorizedToDrop(req, model)); + } + + @Test + public void dropUnauthorizedModel() { + Model model = model( + dataStatement(APPROVED_SUBJECT_URI, UNAPPROVED_PREDICATE_URI), + objectStatement(APPROVED_SUBJECT_URI, APPROVED_PREDICATE_URI, + APPROVED_OBJECT_URI)); + assertEquals("unauthorized model", false, + PolicyHelper.isAuthorizedToDrop(req, model)); + } + + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + /** Build a data statement. */ + private Statement dataStatement(String subjectUri, String predicateUri) { + Model model = ModelFactory.createDefaultModel(); + Resource subject = model.createResource(subjectUri); + Property predicate = model.createProperty(predicateUri); + return model.createStatement(subject, predicate, "whoCares?"); + } + + /** Build a object statement. */ + private Statement objectStatement(String subjectUri, String predicateUri, + String objectUri) { + Model model = ModelFactory.createDefaultModel(); + Resource subject = model.createResource(subjectUri); + Resource object = model.createResource(objectUri); + Property predicate = model.createProperty(predicateUri); + return model.createStatement(subject, predicate, object); + } + + /** Build a model. */ + private Model model(Statement... stmts) { + Model model = ModelFactory.createDefaultModel(); + model.add(stmts); + return model; + } + + // ---------------------------------------------------------------------- + // Helper classes + // ---------------------------------------------------------------------- + + private static class MySimplePolicy implements PolicyIface { + @Override + public PolicyDecision isAuthorized(IdentifierBundle whoToAuth, + RequestedAction whatToAuth) { + if (whatToAuth instanceof AbstractDataPropertyAction) { + return isAuthorized((AbstractDataPropertyAction) whatToAuth); + } else if (whatToAuth instanceof AbstractObjectPropertyAction) { + return isAuthorized((AbstractObjectPropertyAction) whatToAuth); + } else { + return inconclusive(); + } + } + + private PolicyDecision isAuthorized( + AbstractDataPropertyAction whatToAuth) { + if ((APPROVED_SUBJECT_URI.equals(whatToAuth.getSubjectUri())) + && (APPROVED_PREDICATE_URI.equals(whatToAuth + .getPredicateUri()))) { + return authorized(); + } else { + return inconclusive(); + } + } + + private PolicyDecision isAuthorized( + AbstractObjectPropertyAction whatToAuth) { + if ((APPROVED_SUBJECT_URI.equals(whatToAuth.uriOfSubject)) + && (APPROVED_PREDICATE_URI + .equals(whatToAuth.uriOfPredicate)) + && (APPROVED_OBJECT_URI.equals(whatToAuth.uriOfObject))) { + return authorized(); + } else { + return inconclusive(); + } + } + + private PolicyDecision authorized() { + return new BasicPolicyDecision(Authorization.AUTHORIZED, ""); + } + + private PolicyDecision inconclusive() { + return new BasicPolicyDecision(Authorization.INCONCLUSIVE, ""); + } + } + +}