diff --git a/productMods/WEB-INF/web.xml b/productMods/WEB-INF/web.xml
index 66f81cd9..a66420ca 100644
--- a/productMods/WEB-INF/web.xml
+++ b/productMods/WEB-INF/web.xml
@@ -166,8 +166,7 @@
- edu.cornell.mannlib.vitro.webapp.auth.policy.specialrelationships.SelfEditorRelationshipPolicy$Setup
-
+ edu.cornell.mannlib.vivo.auth.policy.SelfEditorRelationshipPolicy$Setup
diff --git a/src/edu/cornell/mannlib/vivo/auth/policy/SelfEditorRelationshipPolicy.java b/src/edu/cornell/mannlib/vivo/auth/policy/SelfEditorRelationshipPolicy.java
new file mode 100644
index 00000000..cbbabc2b
--- /dev/null
+++ b/src/edu/cornell/mannlib/vivo/auth/policy/SelfEditorRelationshipPolicy.java
@@ -0,0 +1,391 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+package edu.cornell.mannlib.vivo.auth.policy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.hp.hpl.jena.ontology.OntModel;
+
+import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
+import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasAssociatedIndividual;
+import edu.cornell.mannlib.vitro.webapp.auth.policy.ServletPolicyList;
+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.specialrelationships.AbstractRelationshipPolicy;
+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;
+import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup;
+
+/**
+ * Permit self-editors to edit the properties of classes with which they share a
+ * special relationship. So for example:
+ *
+ * A self-editor may edit properties of an InformationResource for which he is
+ * an author, an editor, or in which he is featured.
+ *
+ * A self-editor may edit properties of a Project in which he plays a clinical
+ * role.
+ *
+ * Etc.
+ *
+ * NOTE: properties or resources which are restricted by namespace or by access
+ * setting will still not be editable, even if this special relationship
+ * applies.
+ *
+ * NOTE: This could be further generalized by building a list of authorizing
+ * relationships, where each relationship may specify a type of object, a
+ * relating property (or chain of properties), and a text message describing the
+ * relationship (to be used in the decision). We could go even farther and drive
+ * this from an XML config file, so site administrators could configure it
+ * themselves. A great tool for this is the one used to process the Tomcat
+ * server.xml file, see http://commons.apache.org/digester/
+ */
+public class SelfEditorRelationshipPolicy extends AbstractRelationshipPolicy
+ implements PolicyIface {
+ private static final Log log = LogFactory
+ .getLog(SelfEditorRelationshipPolicy.class);
+
+ private static final String NS_CORE = "http://vivoweb.org/ontology/core#";
+ private static final String URI_INFORMATION_RESOURCE_TYPE = NS_CORE
+ + "InformationResource";
+ private static final String URI_EDITOR_PROPERTY = "http://purl.org/ontology/bibo/editor";
+ private static final String URI_FEATURES_PROPERTY = NS_CORE + "features";
+ private static final String URI_IN_AUTHORSHIP_PROPERTY = NS_CORE
+ + "informationResourceInAuthorship";
+ private static final String URI_LINKED_AUTHOR_PROPERTY = NS_CORE
+ + "linkedAuthor";
+
+ private static final String URI_GRANT_TYPE = NS_CORE + "Grant";
+ private static final String URI_RELATED_ROLE_PROPERTY = NS_CORE
+ + "relatedRole";
+ private static final String URI_PRINCIPAL_INVESTIGATOR_OF_PROPERTY = NS_CORE
+ + "principalInvestigatorRoleOf";
+ private static final String URI_CO_PRINCIPAL_INVESTIGATOR_OF_PROPERTY = NS_CORE
+ + "co-PrincipalInvestigatorRoleOf";
+
+ private static final String URI_PROJECT_TYPE = NS_CORE + "Project";
+ private static final String URI_SERVICE_TYPE = NS_CORE + "Service";
+ private static final String URI_CLINICAL_ROLE_OF_PROPERTY = NS_CORE
+ + "clinicalRoleOf";
+
+ private static final String URI_PRESENTATION_TYPE = NS_CORE
+ + "Presentation";
+ private static final String URI_PRESENTER_ROLE_OF_PROPERTY = NS_CORE
+ + "presenterRoleOf";
+
+ private static final String URI_COURSE_TYPE = NS_CORE + "Course";
+ private static final String URI_TEACHER_ROLE_OF_PROPERTY = NS_CORE
+ + "teacherRoleOf";
+
+ private static final String URI_ADVISING_RELATIONSHIP_TYPE = NS_CORE
+ + "AdvisingRelationship";
+ private static final String URI_ADVISOR_PROPERTY = NS_CORE + "advisor";
+
+ public SelfEditorRelationshipPolicy(ServletContext ctx, OntModel model) {
+ super(ctx, model);
+ }
+
+ @Override
+ public PolicyDecision isAuthorized(IdentifierBundle whoToAuth,
+ RequestedAction whatToAuth) {
+ PolicyDecision decision = null;
+
+ if (whatToAuth == null) {
+ decision = inconclusiveDecision("whatToAuth was null");
+ } else if (whatToAuth instanceof AbstractDataPropertyAction) {
+ decision = isAuthorized(whoToAuth,
+ distill((AbstractDataPropertyAction) whatToAuth));
+ } else if (whatToAuth instanceof AbstractObjectPropertyAction) {
+ decision = isAuthorized(whoToAuth,
+ distill((AbstractObjectPropertyAction) whatToAuth));
+ } else {
+ decision = inconclusiveDecision("Does not authorize "
+ + whatToAuth.getClass().getSimpleName() + " actions");
+ }
+
+ if (decision == null) {
+ return userNotAuthorizedToStatement();
+ } else {
+ return decision;
+ }
+ }
+
+ private DistilledAction distill(AbstractDataPropertyAction action) {
+ return new DistilledAction(action.getPredicateUri(),
+ action.getSubjectUri());
+ }
+
+ private DistilledAction distill(AbstractObjectPropertyAction action) {
+ return new DistilledAction(action.uriOfPredicate, action.uriOfSubject,
+ action.uriOfObject);
+ }
+
+ private PolicyDecision isAuthorized(IdentifierBundle ids,
+ DistilledAction action) {
+ List userUris = new ArrayList(
+ HasAssociatedIndividual.getIndividualUris(ids));
+
+ if (userUris.isEmpty()) {
+ return inconclusiveDecision("Not self-editing.");
+ }
+
+ if (!canModifyPredicate(action.predicateUri)) {
+ return cantModifyPredicate(action.predicateUri);
+ }
+
+ for (String resourceUri : action.resourceUris) {
+ if (!canModifyResource(resourceUri)) {
+ return cantModifyResource(resourceUri);
+ }
+ }
+
+ for (String resourceUri : action.resourceUris) {
+ if (isInformationResource(resourceUri)) {
+ if (anyUrisInCommon(userUris, getUrisOfEditors(resourceUri))) {
+ return authorizedEditor(resourceUri);
+ }
+ if (anyUrisInCommon(userUris, getUrisOfAuthors(resourceUri))) {
+ return authorizedAuthor(resourceUri);
+ }
+ if (anyUrisInCommon(userUris, getUrisOfFeatured(resourceUri))) {
+ return authorizedFeatured(resourceUri);
+ }
+ }
+ if (isGrant(resourceUri)) {
+ if (anyUrisInCommon(userUris,
+ getUrisOfPrincipalInvestigators(resourceUri))) {
+ return authorizedPI(resourceUri);
+ }
+ if (anyUrisInCommon(userUris,
+ getUrisOfCoPrincipalInvestigators(resourceUri))) {
+ return authorizedCoPI(resourceUri);
+ }
+ }
+ if (isProject(resourceUri) || isService(resourceUri)) {
+ if (anyUrisInCommon(userUris,
+ getUrisOfClinicalAgents(resourceUri))) {
+ return authorizedClinicalAgent(resourceUri);
+ }
+ }
+ if (isPresentation(resourceUri)) {
+ if (anyUrisInCommon(userUris, getUrisOfPresenters(resourceUri))) {
+ return authorizedPresenter(resourceUri);
+ }
+ }
+ if (isCourse(resourceUri)) {
+ if (anyUrisInCommon(userUris, getUrisOfTeachers(resourceUri))) {
+ return authorizedTeacher(resourceUri);
+ }
+ }
+ if (isAdvisingRelationship(resourceUri)) {
+ if (anyUrisInCommon(userUris, getUrisOfAdvisors(resourceUri))) {
+ return authorizedAdvisor(resourceUri);
+ }
+ }
+ }
+
+ return userNotAuthorizedToStatement();
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName()
+ + ": information resources, grants, projects, etc. - "
+ + hashCode();
+ }
+
+ // ----------------------------------------------------------------------
+ // methods for InformationResource
+ // ----------------------------------------------------------------------
+
+ private boolean isInformationResource(String resourceUri) {
+ return isResourceOfType(resourceUri, URI_INFORMATION_RESOURCE_TYPE);
+ }
+
+ private List getUrisOfEditors(String resourceUri) {
+ return getObjectsOfProperty(resourceUri, URI_EDITOR_PROPERTY);
+ }
+
+ private List getUrisOfFeatured(String resourceUri) {
+ return getObjectsOfProperty(resourceUri, URI_FEATURES_PROPERTY);
+ }
+
+ private List getUrisOfAuthors(String resourceUri) {
+ return getObjectsOfLinkedProperty(resourceUri,
+ URI_IN_AUTHORSHIP_PROPERTY, URI_LINKED_AUTHOR_PROPERTY);
+ }
+
+ private PolicyDecision authorizedEditor(String uri) {
+ return authorizedDecision("User is an editor of " + uri);
+ }
+
+ private PolicyDecision authorizedAuthor(String uri) {
+ return authorizedDecision("User is author of " + uri);
+ }
+
+ private PolicyDecision authorizedFeatured(String uri) {
+ return authorizedDecision("User is featured in " + uri);
+ }
+
+ // ----------------------------------------------------------------------
+ // methods for Grant
+ // ----------------------------------------------------------------------
+
+ private boolean isGrant(String resourceUri) {
+ return isResourceOfType(resourceUri, URI_GRANT_TYPE);
+ }
+
+ private List getUrisOfPrincipalInvestigators(String resourceUri) {
+ return getObjectsOfLinkedProperty(resourceUri,
+ URI_RELATED_ROLE_PROPERTY,
+ URI_PRINCIPAL_INVESTIGATOR_OF_PROPERTY);
+ }
+
+ private List getUrisOfCoPrincipalInvestigators(String resourceUri) {
+ return getObjectsOfLinkedProperty(resourceUri,
+ URI_RELATED_ROLE_PROPERTY,
+ URI_CO_PRINCIPAL_INVESTIGATOR_OF_PROPERTY);
+ }
+
+ private PolicyDecision authorizedPI(String resourceUri) {
+ return authorizedDecision("User is Principal Investigator of "
+ + resourceUri);
+ }
+
+ private PolicyDecision authorizedCoPI(String resourceUri) {
+ return authorizedDecision("User is Co-Principal Investigator of "
+ + resourceUri);
+ }
+
+ // ----------------------------------------------------------------------
+ // methods for Project or Service
+ // ----------------------------------------------------------------------
+
+ private boolean isProject(String resourceUri) {
+ return isResourceOfType(resourceUri, URI_PROJECT_TYPE);
+ }
+
+ private boolean isService(String resourceUri) {
+ return isResourceOfType(resourceUri, URI_SERVICE_TYPE);
+ }
+
+ private List getUrisOfClinicalAgents(String resourceUri) {
+ return getObjectsOfLinkedProperty(resourceUri,
+ URI_RELATED_ROLE_PROPERTY, URI_CLINICAL_ROLE_OF_PROPERTY);
+ }
+
+ private PolicyDecision authorizedClinicalAgent(String resourceUri) {
+ return authorizedDecision("User has a Clinical Role on " + resourceUri);
+ }
+
+ // ----------------------------------------------------------------------
+ // methods for Presentation
+ // ----------------------------------------------------------------------
+
+ private boolean isPresentation(String resourceUri) {
+ return isResourceOfType(resourceUri, URI_PRESENTATION_TYPE);
+ }
+
+ private List getUrisOfPresenters(String resourceUri) {
+ return getObjectsOfLinkedProperty(resourceUri,
+ URI_RELATED_ROLE_PROPERTY, URI_PRESENTER_ROLE_OF_PROPERTY);
+ }
+
+ private PolicyDecision authorizedPresenter(String resourceUri) {
+ return authorizedDecision("User is a Presenter of " + resourceUri);
+ }
+
+ // ----------------------------------------------------------------------
+ // methods for Course
+ // ----------------------------------------------------------------------
+
+ private boolean isCourse(String resourceUri) {
+ return isResourceOfType(resourceUri, URI_COURSE_TYPE);
+ }
+
+ private List getUrisOfTeachers(String resourceUri) {
+ return getObjectsOfLinkedProperty(resourceUri,
+ URI_RELATED_ROLE_PROPERTY, URI_TEACHER_ROLE_OF_PROPERTY);
+ }
+
+ private PolicyDecision authorizedTeacher(String resourceUri) {
+ return authorizedDecision("User is a Teacher of " + resourceUri);
+ }
+
+ // ----------------------------------------------------------------------
+ // methods for AdvisingRelationship
+ // ----------------------------------------------------------------------
+
+ private boolean isAdvisingRelationship(String resourceUri) {
+ return isResourceOfType(resourceUri, URI_ADVISING_RELATIONSHIP_TYPE);
+ }
+
+ private List getUrisOfAdvisors(String resourceUri) {
+ return getObjectsOfProperty(resourceUri, URI_ADVISOR_PROPERTY);
+ }
+
+ private PolicyDecision authorizedAdvisor(String resourceUri) {
+ return authorizedDecision("User is an Advisor of " + resourceUri);
+ }
+
+ // ----------------------------------------------------------------------
+ // helper classes
+ // ----------------------------------------------------------------------
+
+ /**
+ * This allows us to treat data properties and object properties the same.
+ * It's just that object properties have more resourceUris.
+ */
+ static class DistilledAction {
+ final String[] resourceUris;
+ final String predicateUri;
+
+ public DistilledAction(String predicateUri, String... resourceUris) {
+ this.resourceUris = resourceUris;
+ this.predicateUri = predicateUri;
+ }
+ }
+
+ /**
+ * When the system starts up, install the policy. This class must be a
+ * listener in web.xml
+ *
+ * The CommonIdentifierBundleFactory already creates the IDs we need.
+ */
+ public static class Setup implements ServletContextListener {
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+ ServletContext ctx = sce.getServletContext();
+
+ if (AbortStartup.isStartupAborted(ctx)) {
+ return;
+ }
+
+ try {
+ OntModel ontModel = (OntModel) sce.getServletContext()
+ .getAttribute("jenaOntModel");
+
+ ServletPolicyList.addPolicy(ctx,
+ new SelfEditorRelationshipPolicy(ctx, ontModel));
+ } catch (Exception e) {
+ log.error("could not run " + this.getClass().getSimpleName()
+ + ": " + e);
+ AbortStartup.abortStartup(ctx);
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) { /* nothing */
+ }
+ }
+}
diff --git a/test/edu/cornell/mannlib/vivo/auth/policy/SelfEditorRelationshipPolicyTest.java b/test/edu/cornell/mannlib/vivo/auth/policy/SelfEditorRelationshipPolicyTest.java
new file mode 100644
index 00000000..3cf1e42a
--- /dev/null
+++ b/test/edu/cornell/mannlib/vivo/auth/policy/SelfEditorRelationshipPolicyTest.java
@@ -0,0 +1,441 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+package edu.cornell.mannlib.vivo.auth.policy;
+
+import static edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization.AUTHORIZED;
+import static edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization.INCONCLUSIVE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import stubs.edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionPolicyHelperStub;
+import stubs.javax.servlet.ServletContextStub;
+
+import com.hp.hpl.jena.ontology.OntModel;
+import com.hp.hpl.jena.ontology.OntModelSpec;
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.ModelFactory;
+import com.hp.hpl.jena.rdf.model.Statement;
+import com.hp.hpl.jena.rdf.model.StmtIterator;
+
+import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
+import edu.cornell.mannlib.vitro.webapp.auth.identifier.ArrayIdentifierBundle;
+import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
+import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasAssociatedIndividual;
+import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionPolicyHelper;
+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.requestedAction.admin.ServerStatus;
+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.resource.AddResource;
+import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
+
+/**
+ * Check the relationships in the SelfEditorRelationshipPolicy.
+ *
+ * This only checks the relationships that deal with InformationResources.
+ * Testing the others seems too redundant. If we generalize this to use
+ * configurable relationships, then we'll be able to make more general tests as
+ * well.
+ */
+public class SelfEditorRelationshipPolicyTest extends AbstractTestClass {
+ private static final Log log = LogFactory
+ .getLog(SelfEditorRelationshipPolicyTest.class);
+
+ /** Can edit properties or resources in this namespace. */
+ private static final String NS_PERMITTED = "http://vivo.mydomain.edu/individual/";
+
+ /** Can't edit properties or resources in this namespace. */
+ private static final String NS_RESTRICTED = VitroVocabulary.vitroURI;
+
+ /** The resource type is not checked by the admin restrictor. */
+ private static final String RESOURCE_TYPE = NS_RESTRICTED + "funkyType";
+
+ private static final String URI_PERMITTED_RESOURCE = NS_PERMITTED
+ + "permittedResource";
+ private static final String URI_RESTRICTED_RESOURCE = NS_RESTRICTED
+ + "restrictedResource";
+
+ private static final String URI_PERMITTED_PREDICATE = NS_PERMITTED
+ + "permittedPredicate";
+ private static final String URI_RESTRICTED_PREDICATE = NS_RESTRICTED
+ + "restrictedPredicate";
+
+ /**
+ * Where the model statements are stored for this test.
+ */
+ private static final String N3_DATA_FILENAME = "SelfEditorRelationship"
+ + "PolicyTest.n3";
+
+ /**
+ * These URIs must match the data in the N3 file.
+ */
+ private static final String URI_BOZO = NS_PERMITTED + "bozo";
+ private static final String URI_JOE = NS_PERMITTED + "joe";
+ private static final String URI_NOBODY_WROTE_IT = NS_PERMITTED
+ + "nobodyWroteIt";
+ private static final String URI_BOZO_WROTE_IT = NS_PERMITTED
+ + "bozoWroteIt";
+ private static final String URI_BOZO_EDITED_IT = NS_PERMITTED
+ + "bozoEditedIt";
+ private static final String URI_BOZO_FEATURED_IN_IT = NS_PERMITTED
+ + "bozoFeaturedInIt";
+ private static final String URI_JOE_WROTE_IT = NS_PERMITTED + "joeWroteIt";
+ private static final String URI_JOE_EDITED_IT = NS_PERMITTED
+ + "joeEditedIt";
+ private static final String URI_JOE_FEATURED_IN_IT = NS_PERMITTED
+ + "joeFeaturedInIt";
+
+ private static OntModel ontModel;
+
+ @BeforeClass
+ public static void setupModel() throws IOException {
+ InputStream stream = SelfEditorRelationshipPolicyTest.class
+ .getResourceAsStream(N3_DATA_FILENAME);
+ Model model = ModelFactory.createDefaultModel();
+ model.read(stream, null, "N3");
+ stream.close();
+
+ ontModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM,
+ model);
+ ontModel.prepare();
+ dumpModel();
+ }
+
+ private SelfEditorRelationshipPolicy policy;
+ private RequestedAction action;
+
+ @Before
+ public void setupPolicy() {
+ ServletContextStub ctx = new ServletContextStub();
+ PropertyRestrictionPolicyHelper prph = PropertyRestrictionPolicyHelperStub
+ .getInstance(new String[] { NS_RESTRICTED });
+ PropertyRestrictionPolicyHelper.setBean(ctx, prph);
+
+ policy = new SelfEditorRelationshipPolicy(ctx, ontModel);
+ }
+
+ private IdentifierBundle idNobody;
+ private IdentifierBundle idBozo;
+ private IdentifierBundle idJoe;
+ private IdentifierBundle idBozoAndJoe;
+
+ @Before
+ public void setupIdBundles() {
+ idNobody = new ArrayIdentifierBundle();
+
+ idBozo = new ArrayIdentifierBundle();
+ idBozo.add(makeSelfEditingId(URI_BOZO));
+
+ idJoe = new ArrayIdentifierBundle();
+ idJoe.add(makeSelfEditingId(URI_JOE));
+
+ idBozoAndJoe = new ArrayIdentifierBundle();
+ idBozoAndJoe.add(makeSelfEditingId(URI_BOZO));
+ idBozoAndJoe.add(makeSelfEditingId(URI_JOE));
+ }
+
+ @Before
+ public void setLogging() {
+ // setLoggerLevel(this.getClass(), Level.DEBUG);
+ // setLoggerLevel(InformationResourceEditingPolicy.class, Level.DEBUG);
+ }
+
+ // ----------------------------------------------------------------------
+ // boilerplate tests
+ // ----------------------------------------------------------------------
+
+ @Test
+ public void whoIsNull() {
+ action = new AddResource(RESOURCE_TYPE, URI_PERMITTED_RESOURCE);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(null, action));
+ }
+
+ @Test
+ public void whatIsNull() {
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, null));
+ }
+
+ @Test
+ public void notSelfEditing() {
+ action = new AddResource(RESOURCE_TYPE, URI_PERMITTED_RESOURCE);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idNobody, action));
+ }
+
+ @Test
+ public void requestedActionOutOfScope() {
+ action = new ServerStatus();
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void dataPropSubjectIsRestricted() {
+ action = new AddDataPropStmt(URI_RESTRICTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, "junk", null, null);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void dataPropPredicateIsRestricted() {
+ action = new AddDataPropStmt(URI_JOE_EDITED_IT,
+ URI_RESTRICTED_PREDICATE, "junk", null, null);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void objectPropSubjectIsRestricted() {
+ action = new AddObjectPropStmt(URI_RESTRICTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, URI_JOE_EDITED_IT);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void objectPropPredicateIsRestricted() {
+ action = new AddObjectPropStmt(URI_PERMITTED_RESOURCE,
+ URI_RESTRICTED_PREDICATE, URI_JOE_EDITED_IT);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void objectPropObjectIsRestricted() {
+ action = new AddObjectPropStmt(URI_JOE_EDITED_IT,
+ URI_PERMITTED_PREDICATE, URI_RESTRICTED_RESOURCE);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ // ----------------------------------------------------------------------
+ // InformationResource tests
+ // ----------------------------------------------------------------------
+
+ @Test
+ public void dataPropSubjectIsInfoResourceButNobodyIsSelfEditing() {
+ action = new AddDataPropStmt(URI_JOE_WROTE_IT, URI_PERMITTED_PREDICATE,
+ "junk", null, null);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idNobody, action));
+ }
+
+ @Test
+ public void dataPropSubjectIsInfoResourceButNoAuthorsOrEditorsOrFeatured() {
+ action = new AddDataPropStmt(URI_NOBODY_WROTE_IT,
+ URI_PERMITTED_PREDICATE, "junk", null, null);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ @Test
+ public void dataPropSubjectIsInfoResourceButWrongAuthor() {
+ action = new AddDataPropStmt(URI_BOZO_WROTE_IT,
+ URI_PERMITTED_PREDICATE, "junk", null, null);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void dataPropSubjectIsInfoResourceButWrongEditor() {
+ action = new AddDataPropStmt(URI_BOZO_EDITED_IT,
+ URI_PERMITTED_PREDICATE, "junk", null, null);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void dataPropSubjectIsInfoResourceButWrongFeatured() {
+ action = new AddDataPropStmt(URI_BOZO_FEATURED_IN_IT,
+ URI_PERMITTED_PREDICATE, "junk", null, null);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void dataPropSubjectIsInfoResourceWithSelfEditingAuthor() {
+ action = new AddDataPropStmt(URI_JOE_WROTE_IT, URI_PERMITTED_PREDICATE,
+ "junk", null, null);
+ assertDecision(AUTHORIZED, policy.isAuthorized(idJoe, action));
+ assertDecision(AUTHORIZED, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ @Test
+ public void dataPropSubjectIsInfoResourceWithSelfEditingEditor() {
+ action = new AddDataPropStmt(URI_JOE_EDITED_IT,
+ URI_PERMITTED_PREDICATE, "junk", null, null);
+ assertDecision(AUTHORIZED, policy.isAuthorized(idJoe, action));
+ assertDecision(AUTHORIZED, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ @Test
+ public void dataPropSubjectIsInfoResourceWithSelfEditingFeatured() {
+ action = new AddDataPropStmt(URI_JOE_FEATURED_IN_IT,
+ URI_PERMITTED_PREDICATE, "junk", null, null);
+ assertDecision(AUTHORIZED, policy.isAuthorized(idJoe, action));
+ assertDecision(AUTHORIZED, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ @Test
+ public void objectPropSubjectIsInfoResourceButNobodyIsSelfEditing() {
+ action = new AddObjectPropStmt(URI_JOE_EDITED_IT,
+ URI_PERMITTED_PREDICATE, URI_PERMITTED_RESOURCE);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idNobody, action));
+ }
+
+ @Test
+ public void objectPropSubjectIsInfoResourceButNoAuthorsOrEditorsOrFeatured() {
+ action = new AddObjectPropStmt(URI_NOBODY_WROTE_IT,
+ URI_PERMITTED_PREDICATE, URI_PERMITTED_RESOURCE);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ @Test
+ public void objectPropSubjectIsInfoResourceButWrongAuthor() {
+ action = new AddObjectPropStmt(URI_BOZO_WROTE_IT,
+ URI_PERMITTED_PREDICATE, URI_PERMITTED_RESOURCE);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void objectPropSubjectIsInfoResourceButWrongEditor() {
+ action = new AddObjectPropStmt(URI_BOZO_EDITED_IT,
+ URI_PERMITTED_PREDICATE, URI_PERMITTED_RESOURCE);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void objectPropSubjectIsInfoResourceButWrongFeatured() {
+ action = new AddObjectPropStmt(URI_BOZO_FEATURED_IN_IT,
+ URI_PERMITTED_PREDICATE, URI_PERMITTED_RESOURCE);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void objectPropSubjectIsInfoResourceWithSelfEditingAuthor() {
+ action = new AddObjectPropStmt(URI_JOE_WROTE_IT,
+ URI_PERMITTED_PREDICATE, URI_PERMITTED_RESOURCE);
+ assertDecision(AUTHORIZED, policy.isAuthorized(idJoe, action));
+ assertDecision(AUTHORIZED, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ @Test
+ public void objectPropSubjectIsInfoResourceWithSelfEditingEditor() {
+ action = new AddObjectPropStmt(URI_JOE_EDITED_IT,
+ URI_PERMITTED_PREDICATE, URI_PERMITTED_RESOURCE);
+ assertDecision(AUTHORIZED, policy.isAuthorized(idJoe, action));
+ assertDecision(AUTHORIZED, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ @Test
+ public void objectPropSubjectIsInfoResourceWithSelfEditingFeatured() {
+ action = new AddObjectPropStmt(URI_JOE_FEATURED_IN_IT,
+ URI_PERMITTED_PREDICATE, URI_PERMITTED_RESOURCE);
+ assertDecision(AUTHORIZED, policy.isAuthorized(idJoe, action));
+ assertDecision(AUTHORIZED, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ @Test
+ public void objectPropObjectIsInfoResourcebutNobodyIsSelfEditing() {
+ action = new AddObjectPropStmt(URI_PERMITTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, URI_JOE_EDITED_IT);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idNobody, action));
+ }
+
+ @Test
+ public void objectPropObjectIsInfoResourceButNoAuthorsOrEditors() {
+ action = new AddObjectPropStmt(URI_PERMITTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, URI_NOBODY_WROTE_IT);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ @Test
+ public void objectPropObjectIsInfoResourceButWrongAuthor() {
+ action = new AddObjectPropStmt(URI_PERMITTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, URI_BOZO_WROTE_IT);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void objectPropObjectIsInfoResourceButWrongEditor() {
+ action = new AddObjectPropStmt(URI_PERMITTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, URI_BOZO_EDITED_IT);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void objectPropObjectIsInfoResourceButWrongFeatured() {
+ action = new AddObjectPropStmt(URI_PERMITTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, URI_BOZO_FEATURED_IN_IT);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void objectPropObjectIsInfoResourceWithSelfEditingAuthor() {
+ action = new AddObjectPropStmt(URI_PERMITTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, URI_JOE_WROTE_IT);
+ assertDecision(AUTHORIZED, policy.isAuthorized(idJoe, action));
+ assertDecision(AUTHORIZED, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ @Test
+ public void objectPropObjectIsInfoResourceWithSelfEditingEditor() {
+ action = new AddObjectPropStmt(URI_PERMITTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, URI_JOE_EDITED_IT);
+ assertDecision(AUTHORIZED, policy.isAuthorized(idJoe, action));
+ assertDecision(AUTHORIZED, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ @Test
+ public void objectPropObjectIsInfoResourceWithSelfEditingFeatured() {
+ action = new AddObjectPropStmt(URI_PERMITTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, URI_JOE_FEATURED_IN_IT);
+ assertDecision(AUTHORIZED, policy.isAuthorized(idJoe, action));
+ assertDecision(AUTHORIZED, policy.isAuthorized(idBozoAndJoe, action));
+ }
+
+ // ----------------------------------------------------------------------
+ // Other tests
+ // ----------------------------------------------------------------------
+
+ @Test
+ public void dataPropSubjectIsNotInfoResource() {
+ action = new AddDataPropStmt(URI_PERMITTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, "junk", null, null);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ @Test
+ public void objectPropNeitherSubjectOrObjectIsInfoResource() {
+ action = new AddObjectPropStmt(URI_PERMITTED_RESOURCE,
+ URI_PERMITTED_PREDICATE, URI_PERMITTED_RESOURCE);
+ assertDecision(INCONCLUSIVE, policy.isAuthorized(idJoe, action));
+ }
+
+ // ----------------------------------------------------------------------
+ // helper methods
+ // ----------------------------------------------------------------------
+
+ private HasAssociatedIndividual makeSelfEditingId(String uri) {
+ return new HasAssociatedIndividual(uri);
+ }
+
+ private void assertDecision(Authorization expected, PolicyDecision decision) {
+ log.debug("Decision is: " + decision);
+ assertNotNull("decision exists", decision);
+ assertEquals("authorization", expected, decision.getAuthorized());
+ }
+
+ private static void dumpModel() {
+ if (log.isDebugEnabled()) {
+ StmtIterator stmtIt = ontModel.listStatements();
+ while (stmtIt.hasNext()) {
+ Statement stmt = stmtIt.next();
+ log.debug("stmt: " + stmt);
+ }
+ }
+ }
+}
diff --git a/test/edu/cornell/mannlib/vivo/auth/policy/SelfEditorRelationshipPolicyTest.n3 b/test/edu/cornell/mannlib/vivo/auth/policy/SelfEditorRelationshipPolicyTest.n3
new file mode 100644
index 00000000..39be6f57
--- /dev/null
+++ b/test/edu/cornell/mannlib/vivo/auth/policy/SelfEditorRelationshipPolicyTest.n3
@@ -0,0 +1,147 @@
+# $This file is distributed under the terms of the license in /doc/license.txt$
+
+@prefix rdf: .
+@prefix rdfs: .
+@prefix owl: .
+@prefix foaf: .
+@prefix bib: .
+@prefix core: .
+@prefix mydomain: .
+
+### This file is for the test InformationResourceEditingPolicyTest.java.
+
+#
+# Bozo
+#
+mydomain:bozo
+ a foaf:Agent ;
+ a foaf:Person ;
+ a owl:Thing ;
+ a core:EmeritusProfessor ;
+ rdfs:label "Person, Bozo" ;
+ foaf:firstName "Bozo" ;
+ foaf:lastName "Person" ;
+ core:editorOf mydomain:bozoEditedIt ;
+ core:authorInAuthorship mydomain:authorshipBozo ;
+ .
+
+#
+# Joe
+#
+mydomain:joe
+ a foaf:Agent ;
+ a foaf:Person ;
+ a owl:Thing ;
+ a core:EmeritusProfessor ;
+ rdfs:label "Person, Joe" ;
+ foaf:firstName "Joe" ;
+ foaf:lastName "Person" ;
+ core:editorOf mydomain:joeEditedIt ;
+ core:authorInAuthorship mydomain:authorshipJoe ;
+ .
+
+#
+# info resource with no author or editor
+#
+mydomain:nobodyWroteIt
+ a core:BlogPosting ;
+ a core:InformationResource ;
+ a bib:Article ;
+ a bib:Document ;
+ a owl:Thing ;
+ rdfs:label "No author or editor" ;
+ .
+
+#
+# info resource with Bozo as author
+#
+mydomain:bozoWroteIt
+ a core:BlogPosting ;
+ a core:InformationResource ;
+ a bib:Article ;
+ a bib:Document ;
+ a owl:Thing ;
+ rdfs:label "Bozo is author" ;
+ core:informationResourceInAuthorship mydomain:authorshipBozo ;
+ .
+
+mydomain:authorshipBozo
+ a core:Authorship ;
+ a core:Relationship ;
+ a owl:Thing ;
+ core:linkedInformationResource mydomain:bozoWroteIt ;
+ core:linkedAuthor mydomain:bozo ;
+ .
+
+#
+# info resource with Bozo as editor
+#
+mydomain:bozoEditedIt
+ a core:BlogPosting ;
+ a core:InformationResource ;
+ a bib:Article ;
+ a bib:Document ;
+ a owl:Thing ;
+ rdfs:label "Bozo is editor" ;
+ bib:editor mydomain:bozo ;
+ .
+
+#
+# info resource with Bozo featured
+#
+mydomain:bozoFeaturedInIt
+ a core:BlogPosting ;
+ a core:InformationResource ;
+ a bib:Article ;
+ a bib:Document ;
+ a owl:Thing ;
+ rdfs:label "Bozo is featured" ;
+ core:features mydomain:bozo ;
+ .
+
+#
+# info resource with Joe as author
+#
+mydomain:joeWroteIt
+ a core:BlogPosting ;
+ a core:InformationResource ;
+ a bib:Article ;
+ a bib:Document ;
+ a owl:Thing ;
+ rdfs:label "Joe is author" ;
+ core:informationResourceInAuthorship mydomain:authorshipJoe ;
+ .
+
+mydomain:authorshipJoe
+ a core:Authorship ;
+ a core:Relationship ;
+ a owl:Thing ;
+ core:linkedInformationResource mydomain:joeWroteIt ;
+ core:linkedAuthor mydomain:joe ;
+ .
+
+#
+# info resource with Joe as editor
+#
+mydomain:joeEditedIt
+ a core:BlogPosting ;
+ a core:InformationResource ;
+ a bib:Article ;
+ a bib:Document ;
+ a owl:Thing ;
+ rdfs:label "Joe is editor" ;
+ bib:editor mydomain:joe ;
+ .
+
+#
+# info resource with Joe featured
+#
+mydomain:joeFeaturedInIt
+ a core:BlogPosting ;
+ a core:InformationResource ;
+ a bib:Article ;
+ a bib:Document ;
+ a owl:Thing ;
+ rdfs:label "Joe is featured" ;
+ core:features mydomain:joe ;
+ .