/* * A CCNx library test. * * Copyright (C) 2009-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.KeyManager; import org.ccnx.ccn.config.SystemConfiguration; import org.ccnx.ccn.config.UserConfiguration; import org.ccnx.ccn.impl.support.Log; import org.ccnx.ccn.io.RepositoryVersionedOutputStream; import org.ccnx.ccn.io.content.Link; import org.ccnx.ccn.profiles.security.access.group.ACL; import org.ccnx.ccn.profiles.security.access.group.Group; import org.ccnx.ccn.profiles.security.access.group.GroupAccessControlManager; import org.ccnx.ccn.profiles.security.access.group.GroupAccessControlProfile; 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; /** * This test relies on org.ccn.ccn.test.profiles.access.TestUserData to generate users * for the access control test. * */ public class GACMNodeKeyDirtyTestRepo { static GroupAccessControlManager acm; static ContentName directoryBase, userKeyStorePrefix, userNamespace, groupNamespace; static final int numberOfusers = 3; static CreateUserData td; static String[] friendlyNames; static final int numberOfGroups = 3; static String[] groupName = new String[numberOfGroups]; static Group[] group = new Group[numberOfGroups]; static ContentName[] node = new ContentName[numberOfGroups]; static CCNHandle handle; @BeforeClass public static void setUpBeforeClass() throws Exception { CCNTestHelper testHelper = new CCNTestHelper(GACMNodeKeyDirtyTestRepo.class); directoryBase = testHelper.getTestNamespace("testInOrder"); userNamespace = GroupAccessControlProfile.userNamespaceName(UserConfiguration.defaultNamespace()); groupNamespace = GroupAccessControlProfile.groupNamespaceName(UserConfiguration.defaultNamespace()); userKeyStorePrefix = new ContentName(UserConfiguration.defaultNamespace(), "_keystore_"); // create user identities with TestUserData Log.info("Creating {0} test users, if they do not already exist.", numberOfusers); td = new CreateUserData(userKeyStorePrefix, numberOfusers, true, "password".toCharArray()); Log.info("Created {0} test users, or retrieved them from repository.", numberOfusers); td.publishUserKeysToRepository(userNamespace); friendlyNames = td.friendlyNames().toArray(new String[0]); // create and register ACM handle = td.getHandleForUser(friendlyNames[0]); acm = new GroupAccessControlManager(directoryBase, groupNamespace, userNamespace, handle); acm.publishMyIdentity(new ContentName(userNamespace, friendlyNames[0]), handle.keyManager().getDefaultPublicKey()); handle.keyManager().publishKeyToRepository(); // create the root ACL // The root has user0 as a manager Link lk = new Link(new ContentName(userNamespace, friendlyNames[0]), ACL.LABEL_MANAGER, null); ArrayList<Link> rootACLcontents = new ArrayList<Link>(); rootACLcontents.add(lk); // it also has me as a manager, which means I'd better publish my identity as well String myUserName = UserConfiguration.userName(); acm.publishMyIdentity(GroupAccessControlProfile.userNamespaceName(userNamespace, myUserName), KeyManager.getDefaultKeyManager().getDefaultPublicKey()); Link mlk = new Link(new ContentName(userNamespace, myUserName), ACL.LABEL_MANAGER, null); rootACLcontents.add(mlk); ACL rootACL = new ACL(rootACLcontents); acm.initializeNamespace(rootACL); // Register ACM so it can be found handle.keyManager().rememberAccessControlManager(acm); } @AfterClass public static void tearDownAfterClass() throws Exception { td.closeAll(); handle.close(); } /** * Ensures that the tests run in the correct order. * @throws Exception */ @Test public void testInOrder() throws Exception { Log.info(Log.FAC_TEST, "Starting testInOrder"); createUserGroups(); createNodeACLs(); writeNodeContent(); addMemberToGroup0(); writeMoreNodeContent(); removeMemberFromGroup0(); writeEvenMoreNodeContent(); Log.info(Log.FAC_TEST, "Completed testInOrder"); } /** * We create the following group structure: * * group1 * | * group0 group2 * / \ / \ * user0 user1 user0 user2 * * @throws Exception */ public void createUserGroups() throws Exception { Random rand = new Random(); // create group0 containing user0 and user1 ArrayList<Link> G0Members = new ArrayList<Link>(); G0Members.add(new Link(new ContentName(userNamespace, friendlyNames[0]))); G0Members.add(new Link(new ContentName(userNamespace, friendlyNames[1]))); groupName[0] = "usergroup0-" + rand.nextInt(10000); group[0] = acm.groupManager().createGroup(groupName[0], G0Members, 0); // create group1 containing group0 ArrayList<Link> G1Members = new ArrayList<Link>(); G1Members.add(new Link(new ContentName(groupNamespace, groupName[0]))); groupName[1] = "usergroup1-" + rand.nextInt(10000); group[1] = acm.groupManager().createGroup(groupName[1], G1Members, 0); // create group2 containing user0 and user2 ArrayList<Link> G2Members = new ArrayList<Link>(); G2Members.add(new Link(new ContentName(userNamespace, friendlyNames[0]))); G2Members.add(new Link(new ContentName(userNamespace, friendlyNames[2]))); groupName[2] = "usergroup2-" + rand.nextInt(10000); group[2] = acm.groupManager().createGroup(groupName[2], G2Members, 0); // check the size of the groups Assert.assertEquals(2, group[0].membershipList().membershipList().size()); Assert.assertEquals(1, group[1].membershipList().membershipList().size()); Assert.assertEquals(2, group[2].membershipList().membershipList().size()); } public void createNodeACLs() throws Exception { Random rand = new Random(); // create nodes [0-2] and corresponding ACLs that make group[i] a manager of node[i]. for (int i=0; i<numberOfGroups; i++) { String nodeName = "node" + i + "-" + rand.nextInt(10000) + ".txt"; node[i] = new ContentName(directoryBase, nodeName); ContentName groupCN = new ContentName(groupNamespace, groupName[i]); Link lk = new Link(groupCN, ACL.LABEL_MANAGER, null); ArrayList<Link> ACLcontents = new ArrayList<Link>(); ACLcontents.add(lk); ACL aclNode = new ACL(ACLcontents); acm.setACL(node[i], aclNode); } } public void writeNodeContent() throws Exception { // write some content in nodes for (int i=0; i<numberOfGroups; i++) { RepositoryVersionedOutputStream rvos = new RepositoryVersionedOutputStream(node[i], handle); rvos.setTimeout(SystemConfiguration.MAX_TIMEOUT); byte [] data = "content".getBytes(); rvos.write(data, 0, data.length); rvos.close(); } // The node keys are not dirty for (int i=0; i<numberOfGroups; i++) { Assert.assertFalse(acm.nodeKeyIsDirty(node[i])); } } public void addMemberToGroup0() throws Exception { // add user2 to group0 ArrayList<Link> membersToAdd = new ArrayList<Link>(); membersToAdd.add(new Link(new ContentName(userNamespace, friendlyNames[2]))); group[0].addMembers(membersToAdd); // check that group0 is now of size 3 Assert.assertEquals(3, group[0].membershipList().membershipList().size()); } public void writeMoreNodeContent() throws Exception { // The node keys are not dirty for (int i=0; i<numberOfGroups; i++) { Assert.assertFalse(acm.nodeKeyIsDirty(node[i])); } // write some content in nodes for (int i=0; i<numberOfGroups; i++) { RepositoryVersionedOutputStream rvos = new RepositoryVersionedOutputStream(node[i], handle); rvos.setTimeout(SystemConfiguration.MAX_TIMEOUT); byte [] data = "more content".getBytes(); rvos.write(data, 0, data.length); rvos.close(); } // The node keys are still not dirty for (int i=0; i<numberOfGroups; i++) { Assert.assertFalse(acm.nodeKeyIsDirty(node[i])); } } public void removeMemberFromGroup0() throws Exception { // delete user1 from group0 ArrayList<Link> membersToRemove = new ArrayList<Link>(); membersToRemove.add(new Link(new ContentName(userNamespace, friendlyNames[1]))); group[0].removeMembers(membersToRemove); // check group0 is of size 2 again Assert.assertEquals(2, group[0].membershipList().membershipList().size()); } public void writeEvenMoreNodeContent() throws Exception { // The node keys are dirty for nodes 0 and 1, but not 2. Thread.sleep(SystemConfiguration.MAX_TIMEOUT); Assert.assertTrue(acm.nodeKeyIsDirty(node[0])); Assert.assertTrue(acm.nodeKeyIsDirty(node[1])); Assert.assertFalse(acm.nodeKeyIsDirty(node[2])); // write some content in nodes for (int i=0; i<numberOfGroups; i++) { RepositoryVersionedOutputStream rvos = new RepositoryVersionedOutputStream(node[i], handle); rvos.setTimeout(SystemConfiguration.MAX_TIMEOUT); byte [] data = "content".getBytes(); rvos.write(data, 0, data.length); rvos.close(); } // The node keys are no longer dirty for (int i=0; i<numberOfGroups; i++) { Assert.assertFalse(acm.nodeKeyIsDirty(node[i])); } } }