RM-477: RM 2.0 does not work with SOLR

* first pass at supporting SOLR in RM2
  * currently requires reimplementation of permissionServiceImpl due to visibility of methods and member variables
  * job execution delayed to try and prevent start up errors
  * fetchSOLR task added to gradle to retrieve SOLR zip from Maven (could do with some scripts to help with setup for module)
  * TODO more testing and refinement of solution



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/BRANCHES/V2.0-BUG-FIX@40344 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2012-08-13 05:45:17 +00:00
parent 23920d760a
commit 3d2a5a0c8c
13 changed files with 3316 additions and 38 deletions

View File

@@ -473,8 +473,11 @@ public class RMAfterInvocationProvider extends RMSecurityCommon
{
inclusionMask.set(i, true);
}
filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(returnedObject.getResultSetMetaData().getLimitedBy(), PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData()
.getSearchParameters()));
filteringResultSet.setResultSetMetaData(
new SimpleResultSetMetaData(
returnedObject.getResultSetMetaData().getLimitedBy(),
PermissionEvaluationMode.EAGER,
returnedObject.getResultSetMetaData().getSearchParameters()));
return filteringResultSet;
}
else
@@ -483,27 +486,37 @@ public class RMAfterInvocationProvider extends RMSecurityCommon
{
inclusionMask.set(i, true);
}
filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(returnedObject.getResultSetMetaData().getLimitedBy(), PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData()
.getSearchParameters()));
filteringResultSet.setResultSetMetaData(
new SimpleResultSetMetaData(
returnedObject.getResultSetMetaData().getLimitedBy(),
PermissionEvaluationMode.EAGER,
returnedObject.getResultSetMetaData().getSearchParameters()));
return filteringResultSet;
}
}
// record the start time
long startTimeMillis = System.currentTimeMillis();
// set the default, unlimited resultset type
filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(returnedObject.getResultSetMetaData().getLimitedBy(), PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData()
.getSearchParameters()));
filteringResultSet.setResultSetMetaData(
new SimpleResultSetMetaData(
returnedObject.getResultSetMetaData().getLimitedBy(),
PermissionEvaluationMode.EAGER,
returnedObject.getResultSetMetaData().getSearchParameters()));
for (int i = 0; i < returnedObject.length(); i++)
{
long currentTimeMillis = System.currentTimeMillis();
if (i >= maxChecks || (currentTimeMillis - startTimeMillis) > maxCheckTime)
{
filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.NUMBER_OF_PERMISSION_EVALUATIONS, PermissionEvaluationMode.EAGER, returnedObject
.getResultSetMetaData().getSearchParameters()));
break;
}
// if (i >= maxChecks || (currentTimeMillis - startTimeMillis) > maxCheckTime)
// {
// filteringResultSet.setResultSetMetaData(
// new SimpleResultSetMetaData(
// LimitBy.NUMBER_OF_PERMISSION_EVALUATIONS,
// PermissionEvaluationMode.EAGER,
// returnedObject.getResultSetMetaData().getSearchParameters()));
// break;
// }
// All permission checks must pass
inclusionMask.set(i, true);

View File

@@ -106,13 +106,14 @@ public class RMSecurityCommon
*/
public int checkRead(NodeRef nodeRef)
{
int result = AccessDecisionVoter.ACCESS_ABSTAIN;
if (nodeRef != null)
{
// now we know the node - we can abstain for certain types and aspects (eg, rm)
return checkRead(nodeRef, false);
result = checkRead(nodeRef, false);
}
return AccessDecisionVoter.ACCESS_ABSTAIN;
return result;
}
/**
@@ -123,35 +124,32 @@ public class RMSecurityCommon
*/
public int checkRead(NodeRef nodeRef, boolean allowDMRead)
{
if (nodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT))
int result = AccessDecisionVoter.ACCESS_ABSTAIN;
if (rmService.isFilePlanComponent(nodeRef) == true)
{
return checkRmRead(nodeRef);
result = checkRmRead(nodeRef);
}
else
else if (allowDMRead == true)
{
if (allowDMRead)
// Check DM read for copy etc
// DM does not grant - it can only deny
if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED)
{
// Check DM read for copy etc
// DM does not grant - it can only deny
if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED)
if (logger.isDebugEnabled())
{
if (logger.isDebugEnabled())
{
logger.debug("\t\tPermission is denied");
Thread.dumpStack();
}
return AccessDecisionVoter.ACCESS_DENIED;
}
else
{
return AccessDecisionVoter.ACCESS_GRANTED;
logger.debug("\t\tPermission is denied");
Thread.dumpStack();
}
result = AccessDecisionVoter.ACCESS_DENIED;
}
else
{
return AccessDecisionVoter.ACCESS_ABSTAIN;
result = AccessDecisionVoter.ACCESS_GRANTED;
}
}
return result;
}
/**

View File

@@ -72,7 +72,7 @@ public class DispositionLifecycleJobExecuter extends RecordsManagementJobExecute
/**
* @see org.alfresco.module.org_alfresco_module_rm.job.RecordsManagementJobExecuter#execute()
*/
public void execute()
public void executeImpl()
{
logger.debug("Job Starting");

View File

@@ -69,7 +69,7 @@ public class NotifyOfRecordsDueForReviewJobExecuter extends RecordsManagementJob
/**
* @see org.alfresco.module.org_alfresco_module_rm.job.RecordsManagementJobExecuter#execute()
*/
public void execute()
public void executeImpl()
{
if (logger.isDebugEnabled())
{

View File

@@ -80,7 +80,7 @@ public class PublishUpdatesJobExecuter extends RecordsManagementJobExecuter
this.behaviourFilter = behaviourFilter;
}
public void execute()
public void executeImpl()
{
if (logger.isDebugEnabled() == true)
{

View File

@@ -20,18 +20,73 @@ package org.alfresco.module.org_alfresco_module_rm.job;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
/**
* Records management job executer base class.
*
* @author Roy Wetherall
*/
public abstract class RecordsManagementJobExecuter implements RecordsManagementModel
public abstract class RecordsManagementJobExecuter extends AbstractLifecycleBean
implements RecordsManagementModel
{
/** Retrying transaction helper */
protected RetryingTransactionHelper retryingTransactionHelper;
/** Indicates whether the application bootstrap is complete or not */
protected boolean bootstrapComplete = false;
/**
* @param retryingTransactionHelper retrying transaction helper
*/
public void setRetryingTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
{
this.retryingTransactionHelper = retryingTransactionHelper;
}
public abstract void execute();
/**
* Executes the jobs work.
*/
public void execute()
{
// jobs not allowed to execute unless bootstrap is complete
if (bootstrapComplete == true)
{
executeImpl();
}
}
/**
* Jobs work implementation.
*/
public abstract void executeImpl();
/**
* @see org.springframework.extensions.surf.util.AbstractLifecycleBean#onBootstrap(org.springframework.context.ApplicationEvent)
*/
@Override
protected void onBootstrap(ApplicationEvent arg0)
{
// record that the bootstrap has complete
bootstrapComplete = true;
}
/**
* @see org.springframework.extensions.surf.util.AbstractLifecycleBean#onShutdown(org.springframework.context.ApplicationEvent)
*/
@Override
protected void onShutdown(ApplicationEvent arg0)
{
// no implementation
}
/**
* @see org.springframework.extensions.surf.util.AbstractLifecycleBean#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
@Override
public void onApplicationEvent(ApplicationEvent arg0)
{
// no implementation
}
}

View File

@@ -0,0 +1,370 @@
package org.alfresco.module.org_alfresco_module_rm.permission;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.domain.permissions.AclDAO;
import org.alfresco.repo.security.permissions.AccessControlEntry;
import org.alfresco.repo.security.permissions.AccessControlList;
import org.alfresco.repo.security.permissions.PermissionEntry;
import org.alfresco.repo.security.permissions.PermissionReference;
import org.alfresco.repo.security.permissions.impl.ModelDAO;
import org.alfresco.repo.security.permissions.impl.PermissionServiceImpl;
import org.alfresco.repo.security.permissions.impl.RequiredPermission;
import org.alfresco.repo.security.permissions.impl.SimplePermissionReference;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
public class OtherImpl extends PermissionServiceImpl
{
static SimplePermissionReference RM_OLD_ALL_PERMISSIONS_REFERENCE = SimplePermissionReference.getPermissionReference(
QName.createQName("", PermissionService.ALL_PERMISSIONS),
PermissionService.ALL_PERMISSIONS);
private SimpleCache<Serializable, Set<String>> rmReadersCache;
private AclDAO rmAclDaoComponent;
private ModelDAO rmModelDao;
public void setRmReadersCache(SimpleCache<Serializable, Set<String>> rmReadersCache)
{
this.rmReadersCache = rmReadersCache;
}
public void setRmAclDAO(AclDAO rmAclDaoComponent)
{
this.rmAclDaoComponent = rmAclDaoComponent;
}
public void setRmModelDAO(ModelDAO rmModelDao)
{
this.rmModelDao = rmModelDao;
}
@Override
public void setAnyDenyDenies(boolean anyDenyDenies)
{
super.setAnyDenyDenies(anyDenyDenies);
rmReadersCache.clear();
}
@Override
public Set<String> getReaders(Long aclId)
{
Set<String> dmReaders = super.getReaders(aclId);
Set<String> rmReaders = rmReadersCache.get(aclId);
if (rmReaders == null)
{
rmReaders = buildRMReaders(aclId);
rmReadersCache.put(aclId, rmReaders);
}
Set<String> result = new HashSet<String>();
result.addAll(dmReaders);
result.addAll(rmReaders);
return result;
}
private Set<String> buildRMReaders(Long aclId)
{
AccessControlList acl = rmAclDaoComponent.getAccessControlList(aclId);
if (acl == null)
{
return Collections.emptySet();
}
HashSet<String> assigned = new HashSet<String>();
HashSet<String> readers = new HashSet<String>();
for (AccessControlEntry ace : acl.getEntries())
{
assigned.add(ace.getAuthority());
}
PermissionReference permissionRef = getPermissionReference(RMPermissionModel.READ_RECORDS);
for (String authority : assigned)
{
RMUnconditionalAclTest rmTest = new RMUnconditionalAclTest(permissionRef);
if (rmTest.evaluate(authority, aclId))
{
readers.add(authority);
}
}
return Collections.unmodifiableSet(readers);
}
/**
* Ignores type and aspect requirements on the node
*
*/
private class RMUnconditionalAclTest
{
/*
* The required permission.
*/
PermissionReference required;
/*
* Granters of the permission
*/
Set<PermissionReference> granters;
/*
* The additional permissions required at the node level.
*/
Set<PermissionReference> nodeRequirements = new HashSet<PermissionReference>();
/*
* Constructor just gets the additional requirements
*/
RMUnconditionalAclTest(PermissionReference required)
{
this.required = required;
// Set the required node permissions
if (required.equals(getPermissionReference(ALL_PERMISSIONS)))
{
nodeRequirements = rmModelDao.getUnconditionalRequiredPermissions(getPermissionReference(PermissionService.FULL_CONTROL), RequiredPermission.On.NODE);
}
else
{
nodeRequirements = rmModelDao.getUnconditionalRequiredPermissions(required, RequiredPermission.On.NODE);
}
if (rmModelDao.getUnconditionalRequiredPermissions(required, RequiredPermission.On.PARENT).size() > 0)
{
throw new IllegalStateException("Parent permissions can not be checked for an acl");
}
if (rmModelDao.getUnconditionalRequiredPermissions(required, RequiredPermission.On.CHILDREN).size() > 0)
{
throw new IllegalStateException("Child permissions can not be checked for an acl");
}
// Find all the permissions that grant the allowed permission
// All permissions are treated specially.
granters = new LinkedHashSet<PermissionReference>(128, 1.0f);
granters.addAll(rmModelDao.getGrantingPermissions(required));
granters.add(getAllPermissionReference());
granters.add(RM_OLD_ALL_PERMISSIONS_REFERENCE);
}
/**
* Internal hook point for recursion
*
* @param authorisations
* @param nodeRef
* @param denied
* @param recursiveIn
* @return true if granted
*/
boolean evaluate(String authority, Long aclId)
{
// Start out true and "and" all other results
boolean success = true;
// Check the required permissions but not for sets they rely on
// their underlying permissions
//if (modelDAO.checkPermission(required))
//{
// We have to do the test as no parent will help us out
success &= hasSinglePermission(authority, aclId);
if (!success)
{
return false;
}
//}
// Check the other permissions required on the node
for (PermissionReference pr : nodeRequirements)
{
// Build a new test
RMUnconditionalAclTest nt = new RMUnconditionalAclTest(pr);
success &= nt.evaluate(authority, aclId);
if (!success)
{
return false;
}
}
return success;
}
boolean hasSinglePermission(String authority, Long aclId)
{
// Check global permission
if (checkGlobalPermissions(authority))
{
return true;
}
if(aclId == null)
{
return false;
}
else
{
return checkRequired(authority, aclId);
}
}
/**
* Check if we have a global permission
*
* @param authorisations
* @return true if granted
*/
private boolean checkGlobalPermissions(String authority)
{
for (PermissionEntry pe : rmModelDao.getGlobalPermissionEntries())
{
if (isGranted(pe, authority))
{
return true;
}
}
return false;
}
/**
* Check that a given authentication is available on a node
*
* @param authorisations
* @param nodeRef
* @param denied
* @return true if a check is required
*/
boolean checkRequired(String authority, Long aclId)
{
AccessControlList acl = rmAclDaoComponent.getAccessControlList(aclId);
if (acl == null)
{
return false;
}
Set<Pair<String, PermissionReference>> denied = new HashSet<Pair<String, PermissionReference>>();
// Check if each permission allows - the first wins.
// We could have other voting style mechanisms here
for (AccessControlEntry ace : acl.getEntries())
{
if (isGranted(ace, authority, denied))
{
return true;
}
}
return false;
}
/**
* Is a permission granted
*
* @param pe -
* the permissions entry to consider
* @param granters -
* the set of granters
* @param authorisations -
* the set of authorities
* @param denied -
* the set of denied permissions/authority pais
* @return true if granted
*/
private boolean isGranted(AccessControlEntry ace, String authority, Set<Pair<String, PermissionReference>> denied)
{
// If the permission entry denies then we just deny
if (ace.getAccessStatus() == AccessStatus.DENIED)
{
denied.add(new Pair<String, PermissionReference>(ace.getAuthority(), ace.getPermission()));
Set<PermissionReference> granters = rmModelDao.getGrantingPermissions(ace.getPermission());
for (PermissionReference granter : granters)
{
denied.add(new Pair<String, PermissionReference>(ace.getAuthority(), granter));
}
// All the things granted by this permission must be
// denied
Set<PermissionReference> grantees = rmModelDao.getGranteePermissions(ace.getPermission());
for (PermissionReference grantee : grantees)
{
denied.add(new Pair<String, PermissionReference>(ace.getAuthority(), grantee));
}
// All permission excludes all permissions available for
// the node.
if (ace.getPermission().equals(getAllPermissionReference()) || ace.getPermission().equals(RM_OLD_ALL_PERMISSIONS_REFERENCE))
{
for (PermissionReference deny : rmModelDao.getAllPermissions())
{
denied.add(new Pair<String, PermissionReference>(ace.getAuthority(), deny));
}
}
return false;
}
// The permission is allowed but we deny it as it is in the denied
// set
if (denied != null)
{
Pair<String, PermissionReference> specific = new Pair<String, PermissionReference>(ace.getAuthority(), required);
if (denied.contains(specific))
{
return false;
}
}
// If the permission has a match in both the authorities and
// granters list it is allowed
// It applies to the current user and it is granted
if (authority.equals(ace.getAuthority()) && granters.contains(ace.getPermission()))
{
{
return true;
}
}
// Default deny
return false;
}
private boolean isGranted(PermissionEntry pe, String authority)
{
// If the permission entry denies then we just deny
if (pe.isDenied())
{
return false;
}
// If the permission has a match in both the authorities and
// granters list it is allowed
// It applies to the current user and it is granted
if (granters.contains(pe.getPermissionReference()) && authority.equals(pe.getAuthority()))
{
{
return true;
}
}
// Default deny
return false;
}
}
}