/* The contents of this file are subject to the license and copyright terms * detailed in the license directory at the root of the source tree (also * available online at http://fedora-commons.org/license/). */ package org.fcrepo.test.api; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.xml.ws.soap.SOAPFaultException; import junit.framework.JUnit4TestAdapter; import org.fcrepo.client.FedoraClient; import org.fcrepo.server.access.FedoraAPIAMTOM; import org.fcrepo.server.management.FedoraAPIMMTOM; import org.fcrepo.server.types.gen.ArrayOfString; import org.fcrepo.server.types.mtom.gen.GetDissemination.Parameters; import org.fcrepo.server.utilities.ServerUtility; import org.fcrepo.server.utilities.StreamUtility; import org.fcrepo.server.utilities.TypeUtility; import org.fcrepo.test.FedoraServerTestCase; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.JUnitCore; /** * Tests involving XACML policies, for API-A and API-M. * <p> * Note: Although these tests can run when API-A AuthN is off, for the best * coverage, make sure the server is configured to authenticate for API-A * access. * </p> * @author Edwin Shin */ public class TestXACMLPolicies extends FedoraServerTestCase { private static FedoraClient s_client; private FedoraClient admin; private FedoraClient testuser1; private FedoraClient testuserroleA; private FedoraClient testuser2; private FedoraClient testuser3; private FedoraClient testuserroleB; private FedoraClient testuserroleC; private FedoraClient testuserroleC2; private FedoraClient testuser4; private File fedoraUsersBackup = null; @BeforeClass public static void bootstrap() throws Exception { s_client = getFedoraClient(); ingestImageManipulationDemoObjects(s_client); ingestSimpleDocumentDemoObjects(s_client); ingestSimpleImageDemoObjects(s_client); } @AfterClass public static void cleanUp() throws Exception { purgeDemoObjects(s_client); s_client.shutdown(); } @Test public void testXACMLMultiOwnerAccess() throws Exception { // demo:MultiOwnerObject is owned by fedoraAdmin and testuser1 final String pid = "test:MultiOwnerObject"; final String owners = "fedoraAdmin,testuser1"; String[] nullModels = null; addTestObject(pid, owners, nullModels); // should only be modifiable by an owner try { assertTrue(canWrite(admin, pid, "testXACMLMultiOwnerAccess")); assertTrue(canWrite(testuser1, pid, "testXACMLMultiOwnerAccess")); assertFalse(canWrite(testuserroleA, pid, "testXACMLMultiOwnerAccess")); } finally { removeTestObject(pid); } } @Test public void testXACMLUnmodifiableContentModel() throws Exception { // test policy disallows modifyObject for test:RestrictedCModel final String unrestrictedCModel = "test:UnrestrictedCModel"; final String restrictedCModel = "test:RestrictedCModel"; final String hasUnrestricted = "test:HasUnrestrictedCModel"; addTestObject(hasUnrestricted, null, unrestrictedCModel); final String hasRestricted = "test:HasRestrictedCModel"; addTestObject(hasRestricted, null, restrictedCModel); final String hasUnrestrictedAndRestricted = "test:HasUnrestrictedAndRestrictedCModel"; addTestObject(hasUnrestrictedAndRestricted, null, unrestrictedCModel, restrictedCModel); final String hasRestrictedAndUnrestricted = "test:HasRestrictedAndUnrestrictedCModel"; addTestObject(hasRestrictedAndUnrestricted, null, restrictedCModel, unrestrictedCModel); try { assertTrue(canWrite(admin, hasUnrestricted,"testXACMLUnmodifiableContentModel")); assertFalse(canWrite(admin, hasRestricted,"testXACMLUnmodifiableContentModel")); assertFalse(canWrite(admin, hasUnrestrictedAndRestricted,"testXACMLUnmodifiableContentModel")); assertFalse(canWrite(admin, hasRestrictedAndUnrestricted,"testXACMLUnmodifiableContentModel")); } finally { removeTestObject(hasUnrestricted); removeTestObject(hasRestricted); removeTestObject(hasUnrestrictedAndRestricted); removeTestObject(hasRestrictedAndUnrestricted); } } private boolean canWrite(FedoraClient client, String pid, String logMessage) throws Exception { FedoraAPIMMTOM apim = client.getAPIMMTOM(); try { apim.modifyObject(pid, null, null, null, logMessage); return true; } catch (Exception e) { e.printStackTrace(); return false; } } @Test public void testXACMLAPIMAccess() throws Exception { String dateOfFirstSuccess = null; String dateOfSecondSuccess = null; String dateOfThirdSuccess = null; String dateOfFourthSuccess = null; String URL1 = getDemoBaseURL() + "/simple-image-demo/col1.jpg"; String URL2 = getDemoBaseURL() + "/simple-image-demo/col2.jpg"; String URL3 = getDemoBaseURL() + "/simple-image-demo/col3.jpg"; Class<?> modDSArgs[] = {String.class, String.class, ArrayOfString.class, String.class, String.class, String.class, String.class, String.class, String.class, String.class, boolean.class}; Object modDSParms1[] = {"demo:5", "THUMBRES_IMG", null, null, null, null, null, null, null, null, false}; Class<?> purgeDSArgs[] = {String.class, String.class, String.class, String.class, String.class, boolean.class}; Object purgeDSParms1[] = {"demo:5", "THUMBRES_IMG", null, null, null, false}; Class<?> setVersionableArgs[] = {String.class, String.class, Boolean.TYPE, String.class}; Object setVersionableFalse[] = {"demo:5", "THUMBRES_IMG", Boolean.FALSE, null}; Object setVersionableTrue[] = {"demo:5", "THUMBRES_IMG", Boolean.TRUE, null}; // APIM access by user without access- should fail // testuserroleA does not have permission to modify a datastream, so this should fail invokeAPIMFailure(testuserroleA, "testuserroleA", "modifyDatastreamByReference", modDSArgs, modDSParms1); //APIM accesses by users with access- should succeed modDSParms1[6] = URL1; dateOfFirstSuccess = invokeAPIMSuccessString(testuser1, "testuser1", "modifyDatastreamByReference", modDSArgs, modDSParms1); System.out.println(" URL = " + modDSParms1[6]); assertTrue(dateOfFirstSuccess != null); System.out.println(" Modify datastream from testuser1 succeeded."); System.out.println("Disabling versioning."); invokeAPIMSuccess(admin, "admin", "setDatastreamVersionable", setVersionableArgs, setVersionableFalse); modDSParms1[6] = URL2; System.out .println("Testing modify datastream from admin with versioning off."); dateOfSecondSuccess = invokeAPIMSuccessString(admin, "admin", "modifyDatastreamByReference", modDSArgs, modDSParms1); System.out.println(" URL = " + modDSParms1[6]); assertTrue(dateOfSecondSuccess != null); System.out.println(" Modify datastream from admin succeeded."); modDSParms1[6] = null; modDSParms1[3] = "The Colliseum with Graffiti"; System.out .println("Testing modify datastream from admin with versioning off just changing label."); dateOfThirdSuccess = invokeAPIMSuccessString(admin, "admin", "modifyDatastreamByReference", modDSArgs, modDSParms1); System.out.println(" Label = " + modDSParms1[3]); assertTrue(dateOfThirdSuccess != null); System.out.println(" Modify datastream from admin succeeded."); System.out.println("Re-enabling versioning."); invokeAPIMSuccess(admin, "admin", "setDatastreamVersionable", setVersionableArgs, setVersionableTrue); modDSParms1[6] = URL3; modDSParms1[3] = null; dateOfFourthSuccess = invokeAPIMSuccessString(testuser1, "testuser1", "modifyDatastreamByReference", modDSArgs, modDSParms1); System.out.println(" URL = " + modDSParms1[6]); assertTrue(dateOfFourthSuccess != null); System.out.println(" Modify datastream from testuser1 succeeded."); // APIM access by user without access- should fail purgeDSParms1[2] = dateOfFirstSuccess; purgeDSParms1[3] = dateOfFourthSuccess; // testuser1 does not have permission to purge a datastream, so this should fail invokeAPIMFailure(testuser1, "testuser1", "purgeDatastream", purgeDSArgs, purgeDSParms1); //APIM access by user without access- should fail // testuserroleA does have permission to to purge a datastream, but only if // datastream is in Deleted(D) state. Datastream here is still in Active(A) state // so this should fail invokeAPIMFailure(testuserroleA, "testuserroleA", "purgeDatastream", purgeDSArgs, purgeDSParms1); //APIM access by user with access- should succeed // fedoraAdmin does have permission to purge a datastream regardless of the // datastream state. Datastream here is in Acive(A) state so purge should still suceed. String purged[] = invokeAPIMSuccessStringArray(admin, "admin", "purgeDatastream", purgeDSArgs, purgeDSParms1); System.out.println(" Checking number of versions purged."); assertEquals(purged.length, 2); System.out.println(" Checking dates of versions purged."); assertEquals(purged[0], dateOfThirdSuccess); assertEquals(purged[1], dateOfFourthSuccess); System.out.println("Purge Datastreams successful."); } @Test public void testXACMLAPIAAccess() throws Exception { if (isAPIAAuthzOn()) { Class<?> getDDArgs[] = {String.class, String.class, String.class}; Object getDDParms[] = {"demo:5", "THUMBRES_IMG", null}; Object getDDParms2[] = {"demo:29", "url", null}; Object getDDParms3[] = {"demo:31", "DS1", null}; Object getDDParms4[] = {"demo:ObjSpecificTest", "DC", null}; Class<?> getDissArgs[] = {String.class, String.class, String.class, Parameters.class, String.class}; Object getDissParms[] = {"demo:5", "demo:1", "getHigh", null, null}; Object getDissParms2[] = {"demo:29", "demo:27", "grayscaleImage", null, null}; Object getDissParms3[] = {"demo:5", "demo:1", "getVeryHigh", null, null}; Class<?> modObjArgs[] = {String.class, String.class, String.class, String.class, String.class}; Object modObjParms[] = {"demo:31", null, null, null, null}; // APIA access by user without access- should fail // testuser2 does not have permission to access api-a at all, so this should fail invokeAPIAFailure(testuser2, "testuser2", "getDatastreamDissemination", getDDArgs, getDDParms); // APIA access by user without access- should fail // testuser3 does not have permission to access Datastreams named THUMBRES_IMG, so this should fail invokeAPIAFailure(testuser3, "testuser3", "getDatastreamDissemination", getDDArgs, getDDParms); // APIA access by user without access- should fail // testuserroleB does not have permission to access HighRes Dissemenations, so this should fail invokeAPIAFailure(testuserroleB, "testuserroleB", "getDissemination", getDissArgs, getDissParms); // APIA access by user without access- should fail // testuser4 does not have permission to access demo:29 at all, so this should fail invokeAPIAFailure(testuser4, "testuser4", "getDatastreamDissemination", getDDArgs, getDDParms2); // APIA access by user without access- should fail // testuser4 does not have permission to access demo:29 at all, so this should fail invokeAPIAFailure(testuser4, "testuser4", "getDissemination", getDissArgs, getDissParms2); // APIA access by user with access- should succeed // testuserroleC does have permission to access demo:5 datastreams, // but custom AttributeFinderModule makes deny-custom-spring-apia policy relevant invokeAPIAFailure(testuserroleC, "testuserroleC", "getDissemination", getDissArgs, getDissParms3); // APIA access by user without access- should fail // testuser1 does not have permission to access demo:29 datastreams, so this should fail invokeAPIAFailure(testuser1, "testuser1", "getDatastreamDissemination", getDDArgs, getDDParms2); // APIA access by user with access- should succeed // testuserroleC does have permission to access demo:29 datastreams, so this should succeed invokeAPIASuccess(testuserroleC, "testuserroleC", "getDatastreamDissemination", getDDArgs, getDDParms2); // Make sure object-specific policies in the POLICY datastream work addObjectSpecificPolicies(); try { // APIA access by user with access- should succeed // testuserroleC does have permission to access demo:ObjSpecificTest datastreams, so this should succeed invokeAPIASuccess(testuserroleC, "testuserroleC", "getDatastreamDissemination", getDDArgs, getDDParms4); // APIA access by user without access- should fail // demo:ObjSpecificTest's object-specific policy explicitly denies access // to user with role roleUntrusted invokeAPIAFailure(testuserroleC2, "testuserroleC2", "getDatastreamDissemination", getDDArgs, getDDParms4); } finally { removeObjectSpecificPolicies(); } // APIA access by user with access- should succeed // testuser1 does have permission to access demo:5 datastreams, so this should succeed invokeAPIASuccess(testuser1, "testuser1", "getDatastreamDissemination", getDDArgs, getDDParms); // APIA access by user who is not owner should fail // testuser1 is not currently owner of demo:31, so this should fail invokeAPIAFailure(testuser1, "testuser1", "getDatastreamDissemination", getDDArgs, getDDParms3); modObjParms[3] = "testuser1"; String dateOfSuccess = invokeAPIMSuccessString(admin, "fedoraAdmin", "modifyObject", modObjArgs, modObjParms); assertTrue(dateOfSuccess != null); System.out.println(" Modify Object from admin succeeded."); // APIA access by user who is now the owner, should succeed // testuser1 is now currently owner of demo:31, so this should succeed invokeAPIASuccess(testuser1, "testuser1", "getDatastreamDissemination", getDDArgs, getDDParms3); modObjParms[3] = "fedoraAdmin"; dateOfSuccess = invokeAPIMSuccessString(admin, "fedoraAdmin", "modifyObject", modObjArgs, modObjParms); assertTrue(dateOfSuccess != null); System.out.println(" Modify Object from admin succeeded."); } else { System.out.println("Authorization is not enabled for APIA"); System.out .println("Testing Policies for APIA access will not work."); } } public void invokeAPIMFailure(FedoraClient user, String username, String functionToTest, Class<?> args[], Object parms[]) { // APIA access by user without access- should fail try { System.out.println("Testing " + functionToTest + " from invalid user: " + username); FedoraAPIMMTOM apim1 = user.getAPIMMTOM(); Method func = apim1.getClass().getMethod(functionToTest, args); func.invoke(apim1, parms); fail("Illegal access allowed"); } catch (InvocationTargetException ite) { Throwable cause = ite.getCause(); if (cause instanceof SOAPFaultException) { SOAPFaultException af = (SOAPFaultException) cause; System.out.println(" Reason = " + af.getMessage()); assertTrue(af.getMessage(), af.getMessage().contains("Authorization Denied")); System.out.println("Access denied correctly"); } else { System.out.println("Got exception: " + cause.getClass().getName()); fail("Illegal access dis-allowed for some other reason: " + cause.getClass().getName()); } } catch (IOException ioe) { System.out.println(" Reason = " + ioe.getMessage()/* * .substring(ioe * . * getMessage() * . * lastIndexOf( * "[")) */); assertTrue(ioe.getMessage().contains("[403 Forbidden]")); System.out.println("Access denied correctly"); // exception was expected, all is A-OK } catch (Exception ae) { String message = "Some other exception: " + ae.toString(); System.out.println(message); fail(message); } } public String invokeAPIMSuccessString(FedoraClient user, String username, String functionToTest, Class<?> args[], Object parms[]) { Object result = invokeAPIMSuccess(user, username, functionToTest, args, parms); return (String) result; } @SuppressWarnings("unchecked") public String[] invokeAPIMSuccessStringArray(FedoraClient user, String username, String functionToTest, Class<?> args[], Object parms[]) { Object result = invokeAPIMSuccess(user, username, functionToTest, args, parms); return ((java.util.ArrayList<String>) result).toArray(new String[0]); } public Object invokeAPIMSuccess(FedoraClient user, String username, String functionToTest, Class<?> args[], Object parms[]) { // APIA access by user with access- should succeed try { // testuser1 does have permission to access demo:5 datastreams, so this should succeed System.out.println("Testing " + functionToTest + " from valid user: " + username); FedoraAPIMMTOM apim1 = user.getAPIMMTOM(); Method func = apim1.getClass().getMethod(functionToTest, args); Object result = func.invoke(apim1, parms); assertTrue(result != null); return result; } catch (InvocationTargetException ite) { Throwable cause = ite.getCause(); if (cause instanceof org.apache.cxf.binding.soap.SoapFault) { org.apache.cxf.binding.soap.SoapFault af = (org.apache.cxf.binding.soap.SoapFault) cause; System.out.println("Got exception: " + af.getClass().getName()); System.out.println("Reason = " + af.getReason()); System.out.println("Message = " + af.getMessage()); fail("Legal access dis-allowed"); } else { System.out.println("Got exception: " + cause.getClass().getName()); fail("Legal access dis-allowed"); } } catch (Exception e) { System.out.println("Got exception: " + e.getClass().getName()); fail("Legal access dis-allowed"); } return null; } public void invokeAPIAFailure(FedoraClient user, String username, String functionToTest, Class<?> args[], Object parms[]) { // APIA access by user without access- should fail try { System.out.println("Testing " + functionToTest + " from invalid user: " + username); FedoraAPIAMTOM apia1 = user.getAPIAMTOM(); Method func = apia1.getClass().getMethod(functionToTest, args); func.invoke(apia1, parms); fail("Illegal access allowed"); } catch (InvocationTargetException ite) { Throwable cause = ite.getCause(); if (cause instanceof SOAPFaultException) { SOAPFaultException sfe = (SOAPFaultException) cause; System.out.println(" Reason = " + sfe.getMessage()); assertTrue(sfe.getMessage(), sfe.getMessage().contains("Authorization Denied")); System.out.println("Access denied correctly"); } else { String message = "Got exception: " + cause.getClass().getName(); System.out.println(message); fail("Illegal access dis-allowed for some other reason: " + message); } } catch (IOException ioe) { System.out.println(" Reason = " + ioe.getMessage().substring(ioe.getMessage() .lastIndexOf("["))); assertTrue(ioe.getMessage().contains("[403 Forbidden]")); System.out.println("Access denied correctly"); // exception was expected, all is A-OK } catch (Exception ae) { String message = "Some other exception: " + ae.toString(); System.out.println(message); fail("Illegal access dis-allowed for some other reason: " + message); } } public Object invokeAPIASuccess(FedoraClient user, String username, String functionToTest, Class<?> args[], Object parms[]) { // APIA access by user with access- should succeed try { // testuser1 does have permission to access demo:5 datastreams, so this should succeed System.out.println("Testing " + functionToTest + " from valid user: " + username); FedoraAPIAMTOM apia1 = user.getAPIAMTOM(); Method func = apia1.getClass().getMethod(functionToTest, args); Object result = func.invoke(apia1, parms); assertTrue(result != null); System.out.println("Access succeeded"); return result; } catch (InvocationTargetException ite) { Throwable cause = ite.getCause(); if (cause instanceof org.apache.cxf.binding.soap.SoapFault) { org.apache.cxf.binding.soap.SoapFault af = (org.apache.cxf.binding.soap.SoapFault) cause; System.out.println("Got exception: " + af.getClass().getName()); System.out.println("Reason = " + af.getReason()); System.out.println("Message = " + af.getMessage()); fail("Legal access dis-allowed"); } else { System.out.println("Got exception: " + cause.getClass().getName()); fail("Legal access dis-allowed"); } } catch (Exception e) { System.out.println("Got exception: " + e.getClass().getName()); fail("Legal access dis-allowed"); } return null; } public boolean isAPIAAuthzOn() throws IOException { File installProperties = new File(FEDORA_HOME, "install/install.properties"); BufferedReader prop = null; try { prop = new BufferedReader(new FileReader(installProperties)); String line = null; while ((line = prop.readLine()) != null) { if (line.startsWith("apia.auth.required")) { if (line.equals("apia.auth.required=true")) { return true; } if (line.equals("apia.auth.required=false")) { return false; } } } return false; } finally { if (prop != null) { prop.close(); } } } public void installJunitPolicies() { String base = System.getProperty("fcrepo-integrationtest-core.classes") != null ? System .getProperty("fcrepo-integrationtest-core.classes") : "src/test/resources/"; File junitDir = new File(base + "XACMLTestPolicies/junit"); System.out.println("Copying Policies For Testing from " + junitDir.getAbsolutePath()); File junitsaveDir = new File(FEDORA_HOME, "data/fedora-xacml-policies/repository-policies/junit"); if (!junitsaveDir.exists()) { junitsaveDir.mkdir(); } File list[] = getFilesInDir(junitDir); traverseAndCopy(list, junitsaveDir); System.out.println("Copying Policies succeeded"); } private void deleteJunitPolicies() { System.out.println("Removing Policies For Testing"); File junitsaveDir = new File(FEDORA_HOME, "data/fedora-xacml-policies/repository-policies/junit"); if (junitsaveDir.exists()) { File list[] = getFilesInDir(junitsaveDir); traverseAndDelete(list); junitsaveDir.delete(); } } private File[] getFilesInDir(File dir) { File srcFiles[] = dir.listFiles(new java.io.FilenameFilter() { @Override public boolean accept(File dir, String name) { if ((name.toLowerCase().startsWith("permit") || name .toLowerCase().startsWith("deny")) && name.endsWith(".xml")) { return true; } return false; } }); return srcFiles; } private void traverseAndCopy(File srcFiles[], File destDir) { for (File element : srcFiles) { File destFile = new File(destDir, element.getName()); System.out.println("Copying policy: " + element.getName()); if (!destFile.exists()) { try { destFile.createNewFile(); } catch (IOException e) { throw new RuntimeException(e); } } copyFile(element, destFile); } } private void traverseAndDelete(File newFiles[]) { for (File element : newFiles) { System.out.println("Deleting policy: " + element.getName()); element.delete(); } } private boolean copyFile(File src, File dest) { InputStream in; try { in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest); StreamUtility.pipeStream(in, out, 1024); return true; } catch (IOException e) { throw new RuntimeException(e); } } private void reloadPolicies() { System.out.println("Reloading Policies..."); try { FedoraClient client = new FedoraClient(ServerUtility.getBaseURL(getProtocol()), getUsername(), getPassword()); client.reloadPolicies(); System.out.println(" Done Reloading Policies"); } catch (Exception e) { throw new RuntimeException(e); } } private void backupFedoraUsersFile() { @SuppressWarnings("deprecation") File srcFile = org.fcrepo.server.security.servletfilters.xmluserfile.FedoraUsers.fedoraUsersXML; fedoraUsersBackup = new File(srcFile.getAbsolutePath() + ".backup"); System.out.println("Backing Up Fedora Users"); if (!fedoraUsersBackup.exists()) { try { fedoraUsersBackup.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } copyFile(srcFile, fedoraUsersBackup); } private void restoreFedoraUsersFile() { System.out.println("Restoring Fedora Users"); if (!fedoraUsersBackup.exists()) { return; } @SuppressWarnings("deprecation") File destFile = org.fcrepo.server.security.servletfilters.xmluserfile.FedoraUsers.fedoraUsersXML; copyFile(fedoraUsersBackup, destFile); } private void createNewFedoraUsersFileWithTestUsers() { String sep = System.getProperty("line.seperator"); if (sep == null) { sep = "\n"; } String data = "<?xml version='1.0' ?> " + sep + "<fedora-users>" + sep + " <user name=\"" + getUsername() + "\" password=\"" + getPassword() + "\">" + sep + " <attribute name=\"fedoraRole\">" + sep + " <value>administrator</value>" + sep + " </attribute>" + sep + " </user>" + sep + " <user name=\"fedoraIntCallUser\" password=\"changeme\">" + sep + " <attribute name=\"fedoraRole\">" + sep + " <value>fedoraInternalCall-1</value>" + sep + " <value>fedoraInternalCall-2</value>" + sep + " </attribute>" + sep + " </user>" + sep + " <user name=\"testuser1\" password=\"testuser1\"/>" + sep + " <user name=\"testuser2\" password=\"testuser2\"/>" + sep + " <user name=\"testuser3\" password=\"testuser3\"/>" + sep + " <user name=\"testuser4\" password=\"testuser4\"/>" + sep + " <user name=\"testuserroleA\" password=\"testuserroleA\">" + sep + " <attribute name=\"fedoraRole\">" + sep + " <value>roleA</value>" + sep + " </attribute>" + sep + " </user>" + sep + " <user name=\"testuserroleB\" password=\"testuserroleB\">" + sep + " <attribute name=\"fedoraRole\">" + sep + " <value>roleB</value>" + sep + " </attribute>" + sep + " </user>" + sep + " <user name=\"testuserroleC\" password=\"testuserroleC\">" + sep + " <attribute name=\"fedoraRole\">" + sep + " <value>roleC</value>" + sep + " </attribute>" + sep + " </user>" + sep + " <user name=\"testuserroleC2\" password=\"testuserroleC2\">" + sep + " <attribute name=\"fedoraRole\">" + sep + " <value>roleC</value>" + sep + " <value>roleUntrusted</value>" + sep + " </attribute>" + sep + " </user>" + sep + " </fedora-users>"; try { @SuppressWarnings("deprecation") FileOutputStream fu = new FileOutputStream( org.fcrepo.server.security.servletfilters.xmluserfile.FedoraUsers.fedoraUsersXML); OutputStreamWriter pw = new OutputStreamWriter(fu); pw.write(data); pw.close(); } catch (IOException e) { throw new RuntimeException(e); } } @Before public void setUp() throws Exception { System.out.println("setting Up XACML test"); admin = getFedoraClient(); backupFedoraUsersFile(); createNewFedoraUsersFileWithTestUsers(); installJunitPolicies(); reloadPolicies(); System.out.println("creating alternate users"); testuser1 = new FedoraClient(getBaseURL(), "testuser1", "testuser1"); testuserroleA = new FedoraClient(getBaseURL(), "testuserroleA", "testuserroleA"); testuser2 = new FedoraClient(getBaseURL(), "testuser2", "testuser2"); testuser3 = new FedoraClient(getBaseURL(), "testuser3", "testuser3"); testuserroleB = new FedoraClient(getBaseURL(), "testuserroleB", "testuserroleB"); testuserroleC = new FedoraClient(getBaseURL(), "testuserroleC", "testuserroleC"); testuserroleC2 = new FedoraClient(getBaseURL(), "testuserroleC2", "testuserroleC2"); testuser4 = new FedoraClient(getBaseURL(), "testuser4", "testuser4"); System.out.println("done setting up"); } private void addObjectSpecificPolicies() { try { StringBuffer xml = new StringBuffer(); xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); xml .append("<foxml:digitalObject VERSION=\"1.1\" PID=\"demo:ObjSpecificTest\" xmlns:foxml=\"info:fedora/fedora-system:def/foxml#\">"); xml.append(" <foxml:objectProperties>"); xml .append(" <foxml:property NAME=\"info:fedora/fedora-system:def/model#state\" VALUE=\"A\"/>"); xml .append(" <foxml:property NAME=\"info:fedora/fedora-system:def/model#label\" VALUE=\"ObjSpecificTest\"/>"); xml .append(" <foxml:property NAME=\"info:fedora/fedora-system:def/model#createdDate\" VALUE=\"2004-12-10T00:21:57Z\"/>"); xml .append(" <foxml:property NAME=\"info:fedora/fedora-system:def/view#lastModifiedDate\" VALUE=\"2004-12-10T00:21:57Z\"/>"); xml.append(" </foxml:objectProperties>"); xml .append(" <foxml:datastream ID=\"POLICY\" CONTROL_GROUP=\"X\" STATE=\"A\">"); xml .append(" <foxml:datastreamVersion FORMAT_URI=\"" + XACML_POLICY1_0.uri + "\" ID=\"POLICY1.0\" MIMETYPE=\"text/xml\" LABEL=\"Policy\">"); xml.append(" <foxml:xmlContent>"); xml .append("<Policy PolicyId=\"POLICY\" RuleCombiningAlgId=\"urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable\""); xml .append(" xmlns=\"urn:oasis:names:tc:xacml:1.0:policy\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"); xml.append(" <Description>"); xml.append(" Denies all to user with id testuserroleC2"); xml.append(" </Description>"); xml.append(" <Target>"); xml.append(" <Subjects>"); xml.append(" <AnySubject/>"); xml.append(" </Subjects>"); xml.append(" <Resources>"); xml.append(" <AnyResource/>"); xml.append(" </Resources>"); xml.append(" <Actions>"); xml.append(" <AnyAction/>"); xml.append(" </Actions>"); xml.append(" </Target>"); xml.append(" <Rule Effect=\"Deny\" RuleId=\"1\">"); xml .append(" <Condition FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:string-is-in\">"); xml .append(" <AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">roleUntrusted</AttributeValue>"); xml .append(" <SubjectAttributeDesignator AttributeId=\"fedoraRole\""); xml .append(" DataType=\"http://www.w3.org/2001/XMLSchema#string\" MustBePresent=\"false\"/>"); xml.append(" </Condition>"); xml.append(" </Rule>"); xml.append("</Policy>"); xml.append(" </foxml:xmlContent>"); xml.append(" </foxml:datastreamVersion>"); xml.append(" </foxml:datastream>"); xml.append("</foxml:digitalObject>"); admin.getAPIMMTOM().ingest(TypeUtility.convertBytesToDataHandler(xml.toString().getBytes("UTF-8")), FOXML1_1.uri, ""); } catch (Exception e) { throw new RuntimeException("Failure adding object-specific " + "policies", e); } } private void removeObjectSpecificPolicies() { try { admin.getAPIMMTOM().purgeObject("demo:ObjSpecificTest", "", false); } catch (Exception e) { throw new RuntimeException("Failure removing object-specific " + "policies", e); } } private void addTestObject(String pid, String ownerId, String... cModelPIDs) { try { StringBuffer xml = new StringBuffer(); xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); xml .append("<foxml:digitalObject VERSION=\"1.1\" PID=\"" + pid + "\" xmlns:foxml=\"info:fedora/fedora-system:def/foxml#\">"); xml.append(" <foxml:objectProperties>"); if (ownerId != null && ownerId.trim().length() > 0) { xml .append(" <foxml:property NAME=\"info:fedora/fedora-system:def/model#ownerId\" VALUE=\""); xml.append(ownerId.trim()); xml.append("\"/>"); } xml .append(" <foxml:property NAME=\"info:fedora/fedora-system:def/model#state\" VALUE=\"A\"/>"); xml .append(" <foxml:property NAME=\"info:fedora/fedora-system:def/model#label\" VALUE=\"MultiOwnerObject\"/>"); xml .append(" <foxml:property NAME=\"info:fedora/fedora-system:def/model#createdDate\" VALUE=\"2004-12-10T00:21:57Z\"/>"); xml .append(" <foxml:property NAME=\"info:fedora/fedora-system:def/view#lastModifiedDate\" VALUE=\"2004-12-10T00:21:57Z\"/>"); xml.append(" </foxml:objectProperties>"); if (cModelPIDs != null) { xml .append("<foxml:datastream CONTROL_GROUP=\"X\" ID=\"RELS-EXT\">"); xml .append(" <foxml:datastreamVersion CREATED=\"2008-07-02T05:09:43.375Z\" FORMAT_URI=\"info:fedora/fedora-system:FedoraRELSExt-1.0\" ID=\"RELS-EXT1.0\" LABEL=\"RDF Statements about this object\" MIMETYPE=\"application/rdf+xml\">"); xml.append(" <foxml:xmlContent>"); xml .append(" <rdf:RDF xmlns:fedora-model=\"info:fedora/fedora-system:def/model#\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">"); xml.append(" <rdf:Description rdf:about=\"info:fedora/" + pid + "\">"); for (String cModelPID : cModelPIDs) { xml .append(" <fedora-model:hasModel rdf:resource=\"info:fedora/" + cModelPID + "\"/>"); } xml.append(" </rdf:Description>"); xml.append(" </rdf:RDF>"); xml.append(" </foxml:xmlContent>"); xml.append(" </foxml:datastreamVersion>"); xml.append("</foxml:datastream>"); } xml.append("</foxml:digitalObject>"); admin.getAPIMMTOM().ingest(TypeUtility.convertBytesToDataHandler(xml.toString().getBytes("UTF-8")), FOXML1_1.uri, ""); } catch (Exception e) { throw new RuntimeException("Failure adding test object: " + pid, e); } } private void removeTestObject(String pid) { try { admin.getAPIMMTOM().purgeObject(pid, "", false); } catch (Exception e) { throw new RuntimeException("Failure removing test object: " + pid, e); } } @After public void tearDown() { restoreFedoraUsersFile(); deleteJunitPolicies(); reloadPolicies(); admin.shutdown(); testuser1.shutdown(); testuserroleA.shutdown(); testuser2.shutdown(); testuser3.shutdown(); testuserroleB.shutdown(); testuserroleC.shutdown(); testuserroleC2.shutdown(); testuser4.shutdown(); } public static junit.framework.Test suite() { return new JUnit4TestAdapter(TestXACMLPolicies.class); } public static void main(String[] args) { JUnitCore.runClasses(TestXACMLPolicies.class); } }