/** * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * * The Apereo Foundation licenses this file to you under the Educational * Community License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License * at: * * http://opensource.org/licenses/ecl2.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * */ package org.opencastproject.authorization.xacml; import org.opencastproject.mediapackage.MediaPackage; import org.opencastproject.mediapackage.MediaPackageBuilderFactory; import org.opencastproject.security.api.AccessControlEntry; import org.opencastproject.security.api.AccessControlList; import org.opencastproject.security.api.AclScope; import org.opencastproject.security.api.DefaultOrganization; import org.opencastproject.security.api.JaxbOrganization; import org.opencastproject.security.api.JaxbRole; import org.opencastproject.security.api.JaxbUser; import org.opencastproject.security.api.Organization; import org.opencastproject.security.api.SecurityService; import org.opencastproject.security.api.User; import org.opencastproject.util.NotFoundException; import org.opencastproject.util.data.Option; import org.opencastproject.workspace.api.Workspace; import org.apache.commons.io.IOUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.HashSet; import java.util.List; import java.util.Set; import de.schlichtherle.io.FileOutputStream; /** * Tests XACML features of the security service */ public class XacmlSecurityTest { /** The logger */ protected static final Logger logger = LoggerFactory.getLogger(XacmlSecurityTest.class); /** The stub workspace to store xacml files */ protected WorkspaceStub workspace = null; /** The username to use with the security service */ protected final String currentUser = "me"; /** The organization to use */ protected final JaxbOrganization organization = new DefaultOrganization(); /** The roles to use with the security service */ protected final Set<JaxbRole> currentRoles = new HashSet<JaxbRole>(); // Override the behavior of the security service to use the current user and roles defined here protected SecurityService securityService = null; protected XACMLAuthorizationService authzService = null; @Before public void setUp() throws Exception { workspace = new WorkspaceStub(); securityService = new SecurityService() { @Override public User getUser() { return new JaxbUser(currentUser, "test", organization, currentRoles); } @Override public void setUser(User user) { throw new UnsupportedOperationException(); } @Override public Organization getOrganization() { return organization; } @Override public void setOrganization(Organization organization) { throw new UnsupportedOperationException(); } @Override public String getUserIP() { return null; } @Override public void setUserIP(String userIP) { } }; authzService = new XACMLAuthorizationService(); authzService.setWorkspace(new WorkspaceStub()); authzService.setSecurityService(securityService); } @After public void tearDown() throws Exception { // workspace.file.delete(); } @Test public void testSecurity() throws Exception { // Create a mediapackage and some role/action tuples MediaPackage mediapackage = MediaPackageBuilderFactory.newInstance().newMediaPackageBuilder().createNew(); AccessControlList aclSeries1 = new AccessControlList(); List<AccessControlEntry> entriesSeries1 = aclSeries1.getEntries(); entriesSeries1.add(new AccessControlEntry("admin", "delete", true)); entriesSeries1.add(new AccessControlEntry("admin", "read", true)); entriesSeries1.add(new AccessControlEntry("student", "read", true)); entriesSeries1.add(new AccessControlEntry("student", "comment", true)); entriesSeries1.add(new AccessControlEntry(DefaultOrganization.DEFAULT_ORGANIZATION_ANONYMOUS, "read", true)); entriesSeries1.add(new AccessControlEntry(DefaultOrganization.DEFAULT_ORGANIZATION_ANONYMOUS, "comment", false)); AccessControlList aclSeries2 = new AccessControlList(); List<AccessControlEntry> entriesSeries2 = aclSeries2.getEntries(); entriesSeries2.add(new AccessControlEntry("admin", "delete", true)); entriesSeries2.add(new AccessControlEntry("admin", "read", true)); entriesSeries2.add(new AccessControlEntry("student", "read", false)); entriesSeries2.add(new AccessControlEntry("student", "comment", false)); entriesSeries2.add(new AccessControlEntry(DefaultOrganization.DEFAULT_ORGANIZATION_ANONYMOUS, "read", true)); entriesSeries2.add(new AccessControlEntry(DefaultOrganization.DEFAULT_ORGANIZATION_ANONYMOUS, "comment", false)); AccessControlList aclEpisode = new AccessControlList(); // Add the security policy to the mediapackage authzService.setAcl(mediapackage, AclScope.Series, aclSeries1); // Ensure that the permissions specified are respected by the security service currentRoles.clear(); currentRoles.add(new JaxbRole("admin", organization, "")); Assert.assertTrue(authzService.hasPermission(mediapackage, "delete")); Assert.assertTrue(authzService.hasPermission(mediapackage, "read")); Assert.assertFalse(authzService.hasPermission(mediapackage, "comment")); currentRoles.clear(); currentRoles.add(new JaxbRole("student", organization, "")); Assert.assertFalse(authzService.hasPermission(mediapackage, "delete")); Assert.assertTrue(authzService.hasPermission(mediapackage, "read")); Assert.assertTrue(authzService.hasPermission(mediapackage, "comment")); currentRoles.clear(); currentRoles.add(new JaxbRole("admin", organization)); authzService.setAcl(mediapackage, AclScope.Episode, aclEpisode); Assert.assertFalse(authzService.hasPermission(mediapackage, "delete")); Assert.assertFalse(authzService.hasPermission(mediapackage, "read")); Assert.assertFalse(authzService.hasPermission(mediapackage, "comment")); mediapackage = authzService.removeAcl(mediapackage, AclScope.Episode); AccessControlList computedAcl = authzService.getActiveAcl(mediapackage).getA(); Assert.assertEquals("ACLs are the same size?", entriesSeries1.size(), computedAcl.getEntries().size()); Assert.assertTrue("ACLs contain the same ACEs?", computedAcl.getEntries().containsAll(entriesSeries1)); authzService.setAcl(mediapackage, AclScope.Series, aclSeries2); currentRoles.clear(); currentRoles.add(new JaxbRole("student", organization)); Assert.assertFalse(authzService.hasPermission(mediapackage, "delete")); Assert.assertFalse(authzService.hasPermission(mediapackage, "read")); Assert.assertFalse(authzService.hasPermission(mediapackage, "comment")); currentRoles.clear(); currentRoles.add(new JaxbRole(DefaultOrganization.DEFAULT_ORGANIZATION_ANONYMOUS, organization, "")); Assert.assertFalse(authzService.hasPermission(mediapackage, "delete")); Assert.assertTrue(authzService.hasPermission(mediapackage, "read")); Assert.assertFalse(authzService.hasPermission(mediapackage, "comment")); } static class WorkspaceStub implements Workspace { /** The default workspace base, this is set to the target directory within the module. */ private static File workspaceBase = new File("target"); @Override public File get(URI uri) throws NotFoundException, IOException { return new File(uri); } @Override public URI getBaseUri() { throw new Error(); } @Override public URI put(String mediaPackageID, String mediaPackageElementID, String fileName, InputStream in) throws IOException { final File file = new File(getURI(mediaPackageID, mediaPackageElementID, fileName)); FileOutputStream out = new FileOutputStream(file); IOUtils.copyLarge(in, out); IOUtils.closeQuietly(out); IOUtils.closeQuietly(in); return file.toURI(); } @Override public URI putInCollection(String collectionId, String fileName, InputStream in) throws IOException { return null; } @Override public URI[] getCollectionContents(String collectionId) throws NotFoundException { throw new Error(); } @Override public void delete(URI uri) throws NotFoundException, IOException { new File(uri).delete(); } @Override public void delete(String mediaPackageID, String mediaPackageElementID) throws NotFoundException, IOException { throw new Error(); } @Override public void deleteFromCollection(String collectionId, String fileName) throws NotFoundException, IOException { throw new Error(); } @Override public URI getURI(String mediaPackageID, String mediaPackageElementID) { throw new Error(); } @Override public URI getCollectionURI(String collectionID, String fileName) { throw new Error(); } @Override public URI moveTo(URI collectionURI, String toMediaPackage, String toMediaPackageElement, String toFileName) throws NotFoundException, IOException { throw new Error(); } @Override public URI copyTo(URI collectionURI, String toMediaPackage, String toMediaPackageElement, String toFileName) throws NotFoundException, IOException { throw new Error(); } @Override public URI getURI(String mediaPackageID, String mediaPackageElementID, String filename) { return new File(workspaceBase, mediaPackageID + "-" + mediaPackageElementID + "-" + filename) .toURI(); } @Override public Option<Long> getTotalSpace() { return Option.<Long> none(); } @Override public Option<Long> getUsableSpace() { return Option.<Long> none(); } @Override public Option<Long> getUsedSpace() { return Option.<Long> none(); } @Override public void cleanup(int maxAge) { // TODO Auto-generated method stub } } }