/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.test.security.acl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import junit.framework.TestCase;
import org.jboss.security.acl.ACLEntry;
import org.jboss.security.acl.ACLEntryImpl;
import org.jboss.security.acl.ACLPersistenceStrategy;
import org.jboss.security.acl.ACLProvider;
import org.jboss.security.acl.ACLProviderImpl;
import org.jboss.security.acl.ACLRegistration;
import org.jboss.security.acl.BasicACLPermission;
import org.jboss.security.acl.BitMaskPermission;
import org.jboss.security.acl.CompositeACLPermission;
import org.jboss.security.acl.JPAPersistenceStrategy;
import org.jboss.security.authorization.AuthorizationException;
import org.jboss.security.authorization.Resource;
import org.jboss.security.identity.Identity;
import org.jboss.security.identity.plugins.IdentityFactory;
/**
* <p>
* This {@code TestCase} tests some ACL use cases.
* </p>
*
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
*/
public class ACLUseTestCase extends TestCase
{
private static int TOTAL_RESOURCES = 5000;
private static final int TOTAL_IDENTITIES = 50;
private TestResource[] resources;
private Identity[] identities;
private ACLPersistenceStrategy strategy;
private ACLRegistration registration;
private ACLProvider provider;
@Override
protected void setUp() throws Exception
{
//Get it as a system property to the test (eg. maven profiles)
String resourcesCount = System.getProperty("acl.resources","100");
TOTAL_RESOURCES = Integer.parseInt(resourcesCount);
this.strategy = new JPAPersistenceStrategy();
this.registration = new TestACLRegistration(strategy);
this.provider = new ACLProviderImpl();
this.provider.setPersistenceStrategy(strategy);
// create the resources used in the tests.
this.resources = new TestResource[TOTAL_RESOURCES];
for (int i = 0; i < TOTAL_RESOURCES; i++)
this.resources[i] = new TestResource(i, "Resource" + i);
// create the identities used in the tests.
this.identities = new Identity[TOTAL_IDENTITIES];
for (int i = 0; i < TOTAL_IDENTITIES; i++)
this.identities[i] = IdentityFactory.createIdentity("Identity" + i);
BitMaskPermission readPermission = BasicACLPermission.READ;
BitMaskPermission noPermission = new CompositeACLPermission();
BitMaskPermission allPermission = new CompositeACLPermission(BasicACLPermission.values());
// register the ACLs for the resources used by the tests.
for (int i = 0; i < TOTAL_RESOURCES; i++)
{
Collection<ACLEntry> entries = new ArrayList<ACLEntry>();
// add the entries ("even" identities can read "even" resources)
for (int j = 0; j < TOTAL_IDENTITIES; j++)
{
if ((i + j) % 2 == 0)
{
// let some identities have all permissions.
if (j % 5 == 0)
entries.add(new ACLEntryImpl(allPermission, this.identities[j]));
else
entries.add(new ACLEntryImpl(readPermission, this.identities[j]));
}
else
{
entries.add(new ACLEntryImpl(noPermission, this.identities[j]));
}
}
this.registration.registerACL(this.resources[i], entries);
}
}
@Override
protected void tearDown() throws Exception
{
// deregisters the ACLs.
for (Resource resource : this.resources)
this.registration.deRegisterACL(resource);
}
/**
* <p>
* Tests the use of ACLs in different use cases, such as filtering, updating and removing
* resources protected by an ACL.
* </p>
*
* @throws Exception if an error occurs when running the test.
*/
public void testACLUseCases() throws Exception
{
// we start by filtering the resources by the identity.
Identity identity = this.identities[0];
TestResource[] filteredResources = this.filterResources(identity);
assertEquals("Unexpected number of resources", TOTAL_RESOURCES / 2, filteredResources.length);
for (TestResource resource : filteredResources)
{
// the "even" identity must be able to see only the "even" resources.
assertTrue(resource.getResourceId() % 2 == 0);
}
// same test, now with an "odd" identity number.
identity = this.identities[1];
filteredResources = this.filterResources(identity);
assertEquals("Unexpected number of resources", TOTAL_RESOURCES / 2, filteredResources.length);
for (TestResource resource : filteredResources)
{
// the identity must be able to see only the "odd" resources.
assertTrue(resource.getResourceId() % 2 == 1);
}
// now try to update some resources using an identity without the appropriate permission (identities[1]).
for (TestResource resource : filteredResources)
{
this.updateResource(resource, identity);
assertEquals("Resource name has changed", "Resource" + resource.getResourceId(), resource.getResourceName());
}
// repeat the test, this time using an identity with the appropriate permission (identities[5] has all perms).
identity = this.identities[5];
for (TestResource resource : filteredResources)
{
this.updateResource(resource, identity);
assertEquals("Resource name hasn't changed as expected", "Changed Name", resource.getResourceName());
}
}
/**
* <p>
* Utility method that uses ACLs to decide which resources the specified identity should be able to read.
* </p>
*
* @param identity the {@code Identity} for which the resources are being filtered.
* @return an array of {@code TestResource} containig the resources the identity is allowed to read.
*/
private TestResource[] filterResources(Identity identity)
{
List<TestResource> filteredResources = new ArrayList<TestResource>();
// iterate through the resources and add those that can be accessed by the identity.
for (TestResource resource : this.resources)
{
boolean isGranted = false;
try
{
// check the identity has the READ permission on the resource.
isGranted = this.provider.isAccessGranted(resource, identity, BasicACLPermission.READ);
}
catch (AuthorizationException ae)
{
fail("Unexpected exception: " + ae.getMessage());
}
if (isGranted)
{
filteredResources.add(resource);
}
}
return filteredResources.toArray(new TestResource[filteredResources.size()]);
}
/**
* <p>
* Utility method that uses ACLs to decide if the specified identity is allowed to update the resource. If
* it is, the resource's name is changed to {@code Changed Name}.
* </p>
*
* @param resource the {@code TestResource} to be updated.
* @param identity the {@code Identity} that wants to update the resource.
*/
private void updateResource(TestResource resource, Identity identity)
{
boolean isGranted = false;
try
{
isGranted = this.provider.isAccessGranted(resource, identity, BasicACLPermission.UPDATE);
}
catch (AuthorizationException ae)
{
fail("Unexpected exception: " + ae.getMessage());
}
if (isGranted)
resource.setResourceName("Changed Name");
}
}