/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco 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 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.test.legacy.capabilities;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.Capability;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.capability.declarative.CapabilityCondition;
import org.alfresco.module.org_alfresco_module_rm.capability.declarative.DeclarativeCapability;
import org.alfresco.module.org_alfresco_module_rm.capability.declarative.DeclarativeCompositeCapability;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanComponentKind;
import org.alfresco.module.org_alfresco_module_rm.role.Role;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.springframework.extensions.webscripts.GUID;
import net.sf.acegisecurity.vote.AccessDecisionVoter;
/**
* Declarative capability unit test
*
* @author Roy Wetherall
*/
public class DeclarativeCapabilityTest extends BaseRMTestCase
{
private NodeRef record;
private NodeRef declaredRecord;
private NodeRef undeclaredRecord;
private NodeRef recordFolderContainsFrozen;
private NodeRef frozenRecord;
private NodeRef frozenRecord2;
private NodeRef frozenRecordFolder;
private NodeRef closedFolder;
private NodeRef moveToFolder;
private NodeRef moveToCategory;
private NodeRef hold;
@Override
protected boolean isUserTest()
{
return true;
}
@Override
protected void setupTestDataImpl()
{
super.setupTestDataImpl();
// Pre-filed content
record = utils.createRecord(rmFolder, "record.txt");
declaredRecord = utils.createRecord(rmFolder, "declaredRecord.txt");
undeclaredRecord = utils.createRecord(rmFolder, "undeclaredRecord.txt");
// Closed folder
closedFolder = recordFolderService.createRecordFolder(rmContainer, "closedFolder");
utils.closeFolder(closedFolder);
// Frozen artifacts
recordFolderContainsFrozen = recordFolderService.createRecordFolder(rmContainer, "containsFrozen");
frozenRecord = utils.createRecord(rmFolder, "frozenRecord.txt");
frozenRecord2 = utils.createRecord(recordFolderContainsFrozen, "frozen2.txt");
frozenRecordFolder = recordFolderService.createRecordFolder(rmContainer, "frozenRecordFolder");
// MoveTo artifacts
moveToFolder = recordFolderService.createRecordFolder(rmContainer, "moveToFolder");
moveToCategory = filePlanService.createRecordCategory(rmContainer, "moveToCategory");
}
@Override
protected void setupTestData()
{
super.setupTestData();
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{
@Override
public Object execute() throws Throwable
{
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
utils.completeRecord(declaredRecord);
utils.completeRecord(frozenRecord);
utils.completeRecord(frozenRecord2);
hold = holdService.createHold(filePlan, GUID.generate(), "reason", "description");
holdService.addToHold(hold, frozenRecord);
holdService.addToHold(hold, frozenRecordFolder);
holdService.addToHold(hold, frozenRecord2);
return null;
}
});
}
@Override
protected void tearDownImpl()
{
// Unfreeze stuff so it can be deleted
holdService.removeFromHold(hold, frozenRecord);
holdService.removeFromHold(hold, frozenRecordFolder);
holdService.removeFromHold(hold, frozenRecord2);
super.tearDownImpl();
}
@Override
protected void setupTestUsersImpl(NodeRef filePlan)
{
super.setupTestUsersImpl(filePlan);
// Give all the users file permission objects
for (String user : testUsers)
{
filePlanPermissionService.setPermission(rmFolder, user, RMPermissionModel.FILING);
filePlanPermissionService.setPermission(rmContainer, user, RMPermissionModel.READ_RECORDS);
filePlanPermissionService.setPermission(moveToFolder, user, RMPermissionModel.READ_RECORDS);
filePlanPermissionService.setPermission(moveToCategory, user, RMPermissionModel.READ_RECORDS);
}
}
public void testDeclarativeCapabilities()
{
Set<Capability> capabilities = capabilityService.getCapabilities();
for (Capability capability : capabilities)
{
if (capability instanceof DeclarativeCapability &&
!(capability instanceof DeclarativeCompositeCapability) &&
!capability.isPrivate() &&
!capability.getName().equals("MoveRecords") &&
!capability.getName().equals("DeleteLinks") &&
!capability.getName().equals("ChangeOrDeleteReferences"))
{
testDeclarativeCapability((DeclarativeCapability)capability);
}
}
}
private void testDeclarativeCapability(final DeclarativeCapability capability)
{
for (String user : testUsers)
{
testDeclarativeCapability(capability, user, filePlan);
testDeclarativeCapability(capability, user, rmContainer);
testDeclarativeCapability(capability, user, rmFolder);
testDeclarativeCapability(capability, user, record);
}
}
private void testDeclarativeCapability(final DeclarativeCapability capability, final String userName, final NodeRef filePlanComponent)
{
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
AccessStatus accessStatus = capability.hasPermission(filePlanComponent);
Set<Role> roles = filePlanRoleService.getRolesByUser(filePlan, userName);
if (roles.isEmpty())
{
assertEquals("User " + userName + " has no RM role so we expect access to be denied for capability " + capability.getName(),
AccessStatus.DENIED,
accessStatus);
}
else
{
// Do the kind check here ...
FilePlanComponentKind actualKind = filePlanService.getFilePlanComponentKind(filePlanComponent);
List<String> kinds = capability.getKinds();
if (kinds == null ||
kinds.contains(actualKind.toString()))
{
Map<String, Boolean> conditions = capability.getConditions();
boolean conditionResult = getConditionResult(filePlanComponent, conditions);
assertEquals("User is expected to only have one role.", 1, roles.size());
Role role = new ArrayList<Role>(roles).get(0);
assertNotNull(role);
Set<Capability> roleCapabilities = role.getCapabilities();
if (roleCapabilities.contains(capability) && conditionResult)
{
assertEquals("User " + userName + " has the role " + role.getDisplayLabel() +
" so we expect access to be allowed for capability " + capability.getName() + " on the object " +
(String)nodeService.getProperty(filePlanComponent, ContentModel.PROP_NAME),
AccessStatus.ALLOWED,
accessStatus);
}
else
{
assertEquals("User " + userName + " has the role " + role.getDisplayLabel() + " so we expect access to be denied for capability " + capability.getName(),
AccessStatus.DENIED,
accessStatus);
}
}
else
{
// Expect fail since the kind is not expected by the capability
assertEquals("NodeRef is of kind" + actualKind + " so we expect access to be denied for capability " + capability.getName(),
AccessStatus.DENIED,
accessStatus);
}
}
return null;
}
}, userName);
}
private boolean getConditionResult(NodeRef nodeRef, Map<String, Boolean> conditions)
{
boolean result = true;
if (conditions != null && conditions.size() != 0)
{
for (Map.Entry<String, Boolean> entry : conditions.entrySet())
{
// Get the condition bean
CapabilityCondition condition = (CapabilityCondition)applicationContext.getBean(entry.getKey());
assertNotNull("Invalid condition name.", condition);
boolean actual = condition.evaluate(nodeRef);
if (actual != entry.getValue().booleanValue())
{
result = false;
break;
}
}
}
return result;
}
/** Specific declarative capability tests */
public void testCreateRecordCapability()
{
final Capability capability = capabilityService.getCapability("CreateRecords");
assertNotNull(capability);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmContainer));
assertEquals(AccessStatus.ALLOWED, capability.hasPermission(rmFolder));
assertEquals(AccessStatus.ALLOWED, capability.hasPermission(record));
assertEquals(AccessStatus.DENIED, capability.hasPermission(declaredRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecordFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(recordFolderContainsFrozen));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(closedFolder));
return null;
}
}, recordsManagerName);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmContainer));
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(record));
assertEquals(AccessStatus.DENIED, capability.hasPermission(declaredRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecordFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(recordFolderContainsFrozen));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(closedFolder));
return null;
}
}, rmUserName);
}
public void testMoveRecordCapability()
{
// grab the move record capability
final Capability capability = capabilityService.getCapability("MoveRecords");
assertNotNull(capability);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
// first take a look at just the record
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmContainer));
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmFolder));
assertEquals(AccessStatus.UNDETERMINED, capability.hasPermission(record));
assertEquals(AccessStatus.UNDETERMINED, capability.hasPermission(declaredRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecordFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(recordFolderContainsFrozen));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(closedFolder));
assertEquals(AccessStatus.UNDETERMINED, capability.hasPermission(undeclaredRecord));
// now lets take a look when we know what the destination is
// NOTE: should be denied since we do not have file permission on the destination folder
// despite having the capability!
assertEquals(AccessDecisionVoter.ACCESS_DENIED, capability.evaluate(record, moveToFolder));
assertEquals(AccessDecisionVoter.ACCESS_DENIED, capability.evaluate(declaredRecord, moveToFolder));
assertEquals(AccessDecisionVoter.ACCESS_DENIED, capability.evaluate(undeclaredRecord, moveToFolder));
assertEquals(AccessDecisionVoter.ACCESS_DENIED, capability.evaluate(frozenRecord, moveToFolder));
return null;
}
}, recordsManagerName);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
for (String user : testUsers)
{
filePlanPermissionService.setPermission(moveToFolder, user, RMPermissionModel.FILING);
}
return null;
}
}, ADMIN_USER);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
// first take a look at just the record
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmContainer));
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmFolder));
assertEquals(AccessStatus.UNDETERMINED, capability.hasPermission(record));
assertEquals(AccessStatus.UNDETERMINED, capability.hasPermission(declaredRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecordFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(recordFolderContainsFrozen));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(closedFolder));
assertEquals(AccessStatus.UNDETERMINED, capability.hasPermission(undeclaredRecord));
// now lets take a look when we know what the destination is
// NOTE: should be allowed now since we have filling permission on the destination folder
assertEquals(AccessDecisionVoter.ACCESS_GRANTED, capability.evaluate(record, moveToFolder));
assertEquals(AccessDecisionVoter.ACCESS_GRANTED, capability.evaluate(declaredRecord, moveToFolder));
assertEquals(AccessDecisionVoter.ACCESS_GRANTED, capability.evaluate(undeclaredRecord, moveToFolder));
assertEquals(AccessDecisionVoter.ACCESS_DENIED, capability.evaluate(frozenRecord, moveToFolder));
return null;
}
}, recordsManagerName);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
// first take a look at just the record
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmContainer));
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(record));
assertEquals(AccessStatus.DENIED, capability.hasPermission(declaredRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecordFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(recordFolderContainsFrozen));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(closedFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(undeclaredRecord));
// now lets take a look when we know what the destination is
// NOTE: should be allowed now since we have filling permission on the destination folder
assertEquals(AccessDecisionVoter.ACCESS_DENIED, capability.evaluate(record, moveToFolder));
assertEquals(AccessDecisionVoter.ACCESS_DENIED, capability.evaluate(declaredRecord, moveToFolder));
assertEquals(AccessDecisionVoter.ACCESS_DENIED, capability.evaluate(undeclaredRecord, moveToFolder));
assertEquals(AccessDecisionVoter.ACCESS_DENIED, capability.evaluate(frozenRecord, moveToFolder));
return null;
}
}, rmUserName);
}
public void testMoveRecordFolderCapability()
{
// grab the move record capability
final Capability capability = capabilityService.getCapability("MoveRecordFolder");
assertNotNull(capability);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
// first take a look at just the record
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmContainer));
assertEquals(AccessStatus.UNDETERMINED, capability.hasPermission(rmFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(record));
assertEquals(AccessStatus.DENIED, capability.hasPermission(declaredRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecordFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(recordFolderContainsFrozen));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(closedFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(undeclaredRecord));
assertEquals(AccessDecisionVoter.ACCESS_DENIED, capability.evaluate(rmFolder, moveToCategory));
return null;
}
}, recordsManagerName);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
for (String user : testUsers)
{
filePlanPermissionService.setPermission(moveToCategory, user, RMPermissionModel.FILING);
}
return null;
}
}, ADMIN_USER);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmContainer));
assertEquals(AccessStatus.UNDETERMINED, capability.hasPermission(rmFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(record));
assertEquals(AccessStatus.DENIED, capability.hasPermission(declaredRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecordFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(recordFolderContainsFrozen));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(closedFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(undeclaredRecord));
assertEquals(AccessDecisionVoter.ACCESS_GRANTED, capability.evaluate(rmFolder, moveToCategory));
return null;
}
}, recordsManagerName);
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmContainer));
assertEquals(AccessStatus.DENIED, capability.hasPermission(rmFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(record));
assertEquals(AccessStatus.DENIED, capability.hasPermission(declaredRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecordFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(recordFolderContainsFrozen));
assertEquals(AccessStatus.DENIED, capability.hasPermission(frozenRecord));
assertEquals(AccessStatus.DENIED, capability.hasPermission(closedFolder));
assertEquals(AccessStatus.DENIED, capability.hasPermission(undeclaredRecord));
assertEquals(AccessDecisionVoter.ACCESS_DENIED, capability.evaluate(rmFolder, moveToCategory));
return null;
}
}, rmUserName);
}
}