/* * A CCNx library test. * * Copyright (C) 2010-2012 Palo Alto Research Center, Inc. * * This work is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. * This work is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ package org.ccnx.ccn.test.profiles.security.access.group; import java.util.ArrayList; import java.util.Random; import junit.framework.Assert; import org.ccnx.ccn.CCNHandle; import org.ccnx.ccn.config.SystemConfiguration; import org.ccnx.ccn.impl.CCNFlowControl.SaveType; import org.ccnx.ccn.impl.support.Log; import org.ccnx.ccn.io.CCNFileInputStream; import org.ccnx.ccn.io.CCNInputStream; import org.ccnx.ccn.io.CCNOutputStream; import org.ccnx.ccn.io.RepositoryFileOutputStream; import org.ccnx.ccn.io.content.Link; import org.ccnx.ccn.profiles.namespace.NamespaceManager; import org.ccnx.ccn.profiles.namespace.ParameterizedName; import org.ccnx.ccn.profiles.security.access.AccessControlManager; import org.ccnx.ccn.profiles.security.access.AccessDeniedException; import org.ccnx.ccn.profiles.security.access.group.ACL; import org.ccnx.ccn.profiles.security.access.group.GroupAccessControlManager; import org.ccnx.ccn.profiles.security.access.group.GroupAccessControlProfile; import org.ccnx.ccn.profiles.security.access.group.ACL.ACLOperation; import org.ccnx.ccn.protocol.ContentName; import org.ccnx.ccn.test.CCNTestHelper; import org.ccnx.ccn.utils.CreateUserData; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; public class MLACReadWriteTestRepo { static CCNHandle _handle; static int domainCount = 2; static ContentName[] domainPrefix, userKeystore, userNamespace, groupNamespace; static String[] userNames = {"Alice", "Bob", "Carol"}; static ContentName baseDirectory, subdirectory, nodeName; static CreateUserData[] cua; static final int blockSize = 8096; static final int contentSizeInBlocks = 100; static Random rnd; static CCNHandle _AliceHandle; static GroupAccessControlManager _AliceACM; int _readsize = 1024; byte [] _read_buffer = new byte[_readsize]; @BeforeClass public static void setUpBeforeClass() throws Exception { rnd = new Random(); _handle = CCNHandle.open(); domainPrefix = new ContentName[domainCount]; userKeystore = new ContentName[domainCount]; userNamespace = new ContentName[domainCount]; groupNamespace = new ContentName[domainCount]; cua = new CreateUserData[domainCount]; // create user identities in different namespaces for (int d=0; d<domainCount; d++) { domainPrefix[d] = ContentName.fromNative("/ccnx.org/domain" + d); userNamespace[d] = GroupAccessControlProfile.userNamespaceName(domainPrefix[d]); userKeystore[d] = new ContentName(userNamespace[d], "_keystore_"); groupNamespace[d] = GroupAccessControlProfile.groupNamespaceName(domainPrefix[d]); cua[d] = new CreateUserData(userKeystore[d], userNames, userNames.length, true, "password".toCharArray()); cua[d].publishUserKeysToRepositorySetLocators(userNamespace[d]); } // create base directory CCNTestHelper testHelper = new CCNTestHelper(MLACReadWriteTestRepo.class); baseDirectory = testHelper.getTestNamespace("PerformanceTest"); // The root ACL at domainPrefix has Alice from domain 0 as a manager ArrayList<Link> ACLcontents = new ArrayList<Link>(); Link lk = new Link(new ContentName(userNamespace[0], userNames[0]), ACL.LABEL_MANAGER, null); ACLcontents.add(lk); ACL rootACL = new ACL(ACLcontents); // Set user and group storage locations as parameterized names for domain 0 and domain 1 ArrayList<ParameterizedName> parameterizedNames = new ArrayList<ParameterizedName>(); for (int d=0; d<domainCount; d++) { ParameterizedName uName = new ParameterizedName("User", userNamespace[d], null); parameterizedNames.add(uName); ParameterizedName gName = new ParameterizedName("Group", groupNamespace[d], null); parameterizedNames.add(gName); } // Set access control policy marker for base directory written as default user. ContentName profileName = ContentName.fromNative(GroupAccessControlManager.PROFILE_NAME_STRING); GroupAccessControlManager.create(baseDirectory, profileName, rootACL, parameterizedNames, null, SaveType.REPOSITORY, CCNHandle.getHandle()); // get handle and ACM for Alice in domain 0 _AliceHandle = cua[0].getHandleForUser(userNames[0]); Assert.assertNotNull(_AliceHandle); NamespaceManager.clearSearchedPathCache(); AccessControlManager.loadAccessControlManagerForNamespace(baseDirectory, _AliceHandle); _AliceACM = (GroupAccessControlManager) AccessControlManager.findACM(baseDirectory, _AliceHandle); Assert.assertNotNull(_AliceACM); // load an ACM for the other users in domain 0 CCNHandle userHandle = null; for (int i=1; i < userNames.length; ++i) { userHandle = cua[0].getHandleForUser(userNames[i]); AccessControlManager.loadAccessControlManagerForNamespace(baseDirectory, userHandle); } // Load an ACM for all users in domain 1. for (int i=0; i < userNames.length; ++i) { userHandle = cua[1].getHandleForUser(userNames[i]); AccessControlManager.loadAccessControlManagerForNamespace(baseDirectory, userHandle); } } @AfterClass public static void tearDownAfterClass() throws Exception { _handle.close(); for( CreateUserData x : cua ) { x.closeAll(); } } @Test public void performanceTest() throws Exception { Log.info(Log.FAC_TEST, "Starting performanceTest"); // Create a new ACL for a subdirectory of baseDirectory. // Set Alice (domain 0) as a manager and Bob and Carol (both domain 1) as readers createSubDirectoryACL(); writeContentInSubdirectory(); try { // Alice (domain 0) has permission to read the file readFileAs(0, userNames[0]); // Bob (domain 1) has permission to read the file readFileAs(1, userNames[1]); } catch (AccessDeniedException ade) { ade.printStackTrace(); Assert.fail(); } // Bob (domain 0) does not have permission to read the file try { readFileAs(0, userNames[1]); Assert.fail(); } catch (AccessDeniedException ade) {} // Alice (domain 1) does not have permission to read the file try { readFileAs(1, userNames[0]); Assert.fail(); } catch (AccessDeniedException ade) {} // Give permission to Alice (domain 1) to read the file updateACL(); // Alice (domain 1) now has permission to read the file try { readFileAs(1, userNames[0]); } catch (AccessDeniedException ade) { Assert.fail(); } Log.info(Log.FAC_TEST, "Completed performanceTest"); } /** * Create a new ACL for a subdirectory of baseDirectory. * Set Alice (domain 0) as a manager and Bob and Carol (both domain 1) as readers */ public void createSubDirectoryACL() { long startTime = System.currentTimeMillis(); try { subdirectory = baseDirectory.append(ContentName.fromNative("/Alice/documents/images/")); ArrayList<Link> ACLcontents = new ArrayList<Link>(); // Alice from domain 0 is a manager ACLcontents.add(new Link(new ContentName(userNamespace[0], userNames[0]), ACL.LABEL_MANAGER, null)); // Bob from domain 1 is a reader ACLcontents.add(new Link(new ContentName(userNamespace[1], userNames[1]), ACL.LABEL_READER, null)); // Carol from domain 1 is a reader ACLcontents.add(new Link(new ContentName(userNamespace[1], userNames[2]), ACL.LABEL_READER, null)); ACL baseDirACL = new ACL(ACLcontents); _AliceACM.setACL(subdirectory, baseDirACL); } catch (Exception e) { Log.warningStackTrace(Log.FAC_TEST, e); Assert.fail(); } Log.info(Log.FAC_TEST, "MLACReadWriteTestRepo: create ACL completed in {0} ms.", (System.currentTimeMillis() - startTime)); } /** * write a file in the baseDirectory */ public void writeContentInSubdirectory() { long startTime = System.currentTimeMillis(); byte [] _write_buffer = new byte[blockSize]; try { nodeName = new ContentName(subdirectory, "randomContent"); CCNOutputStream ostream = new RepositoryFileOutputStream(nodeName, _AliceHandle); ostream.setTimeout(SystemConfiguration.MAX_TIMEOUT); rnd.nextBytes(_write_buffer); for (int i=0; i<contentSizeInBlocks; i++) { ostream.write(_write_buffer, 0, blockSize); } ostream.close(); } catch (Exception e) { e.printStackTrace(); Assert.fail(); } Log.info(Log.FAC_TEST, "MLACReadWriteTestRepo: writing content completed in {0} ms.", (System.currentTimeMillis() - startTime)); } /** * Read the file as the specified user * @param userName the name of the user * @throws AccessDeniedException */ public void readFileAs(int domain, String userName) throws Exception { long startTime = System.currentTimeMillis(); CCNHandle handle = null; try { handle = cua[domain].getHandleForUser(userName); CCNInputStream input = new CCNFileInputStream(nodeName, handle); input.setTimeout(SystemConfiguration.MAX_TIMEOUT); int readcount = 0; int readtotal = 0; while ((readcount = input.read(_read_buffer)) != -1){ readtotal += readcount; } Assert.assertEquals(blockSize * contentSizeInBlocks, readtotal); } // we want to propagate AccessDeniedException, but not IOException. // Since AccessDeniedException is a subclass of IOException, we catch and re-throw it. catch (AccessDeniedException ade) { Log.info(Log.FAC_TEST, "MLACReadWriteTestRepo: determined that user {0} in domain {1} " + " does not read access to the content, in {2} ms.", userName, domain, (System.currentTimeMillis() - startTime)); throw ade; } catch (Exception e) { throw e; } Log.info(Log.FAC_TEST, "MLACReadWriteTestRepo: reading content as {0} succeeded in {1} ms.", userName, (System.currentTimeMillis() - startTime)); } /** * Add Alice (domain 1) as a reader to the ACL on baseDirectory */ public void updateACL() { long startTime = System.currentTimeMillis(); ArrayList<ACLOperation> ACLUpdates = new ArrayList<ACLOperation>(); Link lk = new Link(new ContentName(userNamespace[1], userNames[0])); ACLUpdates.add(ACLOperation.addReaderOperation(lk)); try { _AliceACM.updateACL(subdirectory, ACLUpdates); } catch (Exception e) { e.printStackTrace(); Assert.fail(); } Log.info(Log.FAC_TEST, "MLACReadWriteTestRepo: updated ACL in {1} ms.", (System.currentTimeMillis() - startTime)); } }