/*
* 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.Iterator;
import java.util.LinkedList;
import java.util.Random;
import junit.framework.Assert;
import org.ccnx.ccn.CCNHandle;
import org.ccnx.ccn.config.UserConfiguration;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.io.content.Link;
import org.ccnx.ccn.profiles.security.access.AccessControlProfile;
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.ACL.ACLObject;
import org.ccnx.ccn.protocol.ContentName;
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 GroupAccessControlManagerTestRepo {
static GroupAccessControlManager acm;
static ContentName baseNode, childNode, grandchildNode;
static ContentName userKeyStorePrefix, userNamespace, groupNamespace;
static int userCount = 3;
static CreateUserData td;
static String[] friendlyNames;
static ContentName user0, user1, user2;
static ACL baseACL, childACL;
@AfterClass
public static void tearDownAfterClass() throws Exception {
td.closeAll();
}
@BeforeClass
public static void setUpBeforeClass() throws Exception {
// create base node, child node and grandchild node
Random rand = new Random();
String directoryBase = "/test/AccessControlManagerTestRepo-";
baseNode = ContentName.fromNative(directoryBase + Integer.toString(rand.nextInt(10000)));
childNode = new ContentName(baseNode, "child");
grandchildNode = new ContentName(childNode, "grandchild");
// create user identities with TestUserData
ContentName testPrefix = UserConfiguration.defaultNamespace();
userKeyStorePrefix = new ContentName(testPrefix, AccessControlProfile.ACCESS_CONTROL_MARKER_BYTES);
userNamespace = new ContentName(testPrefix, "home");
groupNamespace = new ContentName(testPrefix, "groups");
td = new CreateUserData(userKeyStorePrefix, userCount, true, "password".toCharArray());
td.publishUserKeysToRepository(userNamespace);
friendlyNames = td.friendlyNames().toArray(new String[0]);
Assert.assertEquals(userCount, friendlyNames.length);
user0 = new ContentName(userNamespace, friendlyNames[0]);
user1 = new ContentName(userNamespace, friendlyNames[1]);
user2 = new ContentName(userNamespace, friendlyNames[2]);
}
/**
* Ensures that the tests run in the correct order.
* @throws Exception
*/
@Test
public void testInOrder() throws Exception {
Log.info(Log.FAC_TEST, "Starting testInOrder");
testSetBaseACL();
testGetBaseACL();
testGetACLFromAncestor();
testSetACL();
testUpdateACLAdd();
testUpdateACLRemove();
deleteACL();
Log.info(Log.FAC_TEST, "Completed testInOrder");
}
/**
* Set the ACL for the base node (we make user 0 a manager of the base node).
* @throws Exception
*/
public void testSetBaseACL() throws Exception {
ArrayList<Link> ACLcontents = new ArrayList<Link>();
Link lk = new Link(user0, "rw+", null);
ACLcontents.add(lk);
baseACL = new ACL(ACLcontents);
CCNHandle handle = td.getHandleForUser(friendlyNames[0]);
acm = new GroupAccessControlManager(baseNode, groupNamespace, userNamespace, handle);
acm.initializeNamespace(baseACL);
}
/**
* Retrieve the ACL for the base node.
* @throws Exception
*/
public void testGetBaseACL() throws Exception {
ACLObject aclo = acm.getEffectiveACLObject(baseNode);
ACL aclRetrieved = aclo.acl();
Assert.assertTrue(aclRetrieved.equals(baseACL));
}
/**
* Retrieve the ACL for the grandchild node.
* This ACL comes from the base node.
* @throws Exception
*/
public void testGetACLFromAncestor() throws Exception {
ACLObject aclo = acm.getEffectiveACLObject(grandchildNode);
Assert.assertTrue(aclo.acl().equals(baseACL));
}
/**
* Interpose a different ACL at the child node (we make user0 a manager and user1 a reader)
* Retrieve the ACL for the grandchild node and check that it now comes
* from the child node.
* @throws Exception
*/
public void testSetACL() throws Exception {
// set interposed ACL
ArrayList<Link> newACLContents = new ArrayList<Link>();
newACLContents.add(new Link(user0, "rw+", null));
newACLContents.add(new Link(user1, "r", null));
childACL = new ACL(newACLContents);
acm.setACL(childNode, childACL);
Thread.sleep(1000);
// retrieve ACL at child node
ACLObject aclo = acm.getEffectiveACLObject(childNode);
Assert.assertTrue(aclo.acl().equals(childACL));
// retrieve ACL at grandchild node
aclo = acm.getEffectiveACLObject(grandchildNode);
Assert.assertTrue(aclo.acl().equals(childACL));
}
/**
* Update the child ACL to add user1 as a writer and user2 as a reader.
* @throws Exception
*/
public void testUpdateACLAdd() throws Exception {
ArrayList<Link> newReaders = new ArrayList<Link>();
newReaders.add(new Link(user2));
acm.addReaders(childNode, newReaders);
ArrayList<Link> newWriters = new ArrayList<Link>();
newWriters.add(new Link(user1));
acm.addWriters(childNode, newWriters);
// get the ACL (at the grandchild node) and check the updates
ACL aclRetrieved = acm.getEffectiveACL(grandchildNode);
LinkedList<Link> childACLLinks = aclRetrieved.contents();
Iterator<Link> iter = childACLLinks.iterator();
// user0 is a manager
Link l = (Link) iter.next();
Assert.assertTrue(l.targetName().equals(user0));
Assert.assertTrue(l.targetLabel().equals("rw+"));
// user2 is a reader
l = (Link) iter.next();
Assert.assertTrue(l.targetName().equals(user2));
Assert.assertTrue(l.targetLabel().equals("r"));
// user1 is a writer
l = (Link) iter.next();
Assert.assertTrue(l.targetName().equals(user1));
Assert.assertTrue(l.targetLabel().equals("rw"));
// there is no other link in the ACL
Assert.assertFalse(iter.hasNext());
}
/**
* Remove user1 as a writer and user2 as a reader of the child node
* @throws Exception
*/
public void testUpdateACLRemove() throws Exception {
// remove user1 as a writer
ArrayList<Link> removedWriters = new ArrayList<Link>();
removedWriters.add(new Link(user1));
Thread.sleep(1000);
acm.removeWriters(childNode, removedWriters);
// remove user2 as a reader
ArrayList<Link> removedReaders = new ArrayList<Link>();
removedReaders.add(new Link(user2));
acm.removeReaders(childNode, removedReaders);
// get the ACL (at the child node) and check the updates
ACL aclRetrieved = acm.getEffectiveACL(grandchildNode);
LinkedList<Link> childACLLinks = aclRetrieved.contents();
Iterator<Link> iter = childACLLinks.iterator();
// user0 is a manager
Link l = (Link) iter.next();
Assert.assertTrue(l.targetName().equals(user0));
Assert.assertTrue(l.targetLabel().equals("rw+"));
// there is no other link in the ACL
Assert.assertFalse(iter.hasNext());
}
/**
* Delete the ACL at the child node.
* Retrieve the ACL for the grandchild node and check that it comes from the base node.
* @throws Exception
*/
public void deleteACL() throws Exception {
acm.deleteACL(childNode);
// retrieve ACL at grandchild node
ACLObject aclo = acm.getEffectiveACLObject(grandchildNode);
Assert.assertTrue(aclo.acl().equals(baseACL));
// TODO need to be sure that people who now have access from the ancestor ACL
// can read content, and new content is protected under the ancestor ACL
}
}