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 ; + .