mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
MNT-22040 Copying nodes that contain sys:pendingFixAcl aspect (#188)
* MNT-22040 - Copying nodes that contain sys:pendingFixAcl aspect * Increased coverage of unit tests * Added public method removePendingAclAspect * Changed the job to use the removePendingAclAspect method instead of repeating the same set of operations twice * Changed method setFixedAcls to use sharedAclToReplace property of node if it has the pendingFixAcl aspect applied instead of using the current shared ACL to be replaced * Added more tests and validations * Fixed cuncurrency issues when updating parent and child at the same time, permissions triggered by a move on a node with a pending acl and permissions needeing to be reapplied on nodes that already have the pending acl aspect * Increase the tree strcuture as sometimes we don't reach the timeout in tests * code cleanup and formatting
This commit is contained in:
@@ -394,6 +394,18 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// When node is copied when the aspect is applied, the sharedACLtoReplace will not match the children's ACLS
|
||||||
|
// to replace, we need to use the current one.
|
||||||
|
Long currentAcl = nodeDAO.getNodeAclId(nodeId);
|
||||||
|
|
||||||
|
if (nodeDAO.hasNodeAspect(nodeId, ContentModel.ASPECT_PENDING_FIX_ACL))
|
||||||
|
{
|
||||||
|
// If node has a pending acl, retrieve the sharedAclToReplace from node property. When the job calls
|
||||||
|
// this, it already does it but on move and copy operations, it uses the new parents old ACL.
|
||||||
|
sharedAclToReplace = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_SHARED_ACL_TO_REPLACE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Lazily retrieve/create the shared ACL
|
// Lazily retrieve/create the shared ACL
|
||||||
if (mergeFrom == null)
|
if (mergeFrom == null)
|
||||||
{
|
{
|
||||||
@@ -407,18 +419,15 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
|
|
||||||
List<NodeIdAndAclId> children = nodeDAO.getPrimaryChildrenAcls(nodeId);
|
List<NodeIdAndAclId> children = nodeDAO.getPrimaryChildrenAcls(nodeId);
|
||||||
|
|
||||||
if(children.size() > 0)
|
|
||||||
{
|
|
||||||
nodeDAO.setPrimaryChildrenSharedAclId(nodeId, sharedAclToReplace, mergeFrom);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!propagateOnChildren)
|
if (!propagateOnChildren)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (NodeIdAndAclId child : children)
|
for (NodeIdAndAclId child : children)
|
||||||
{
|
{
|
||||||
Long acl = child.getAclId();
|
//Use the current ACL instead of the stored value, it could've been changed meanwhile
|
||||||
|
Long acl = nodeDAO.getNodeAclId(child.getId());
|
||||||
|
|
||||||
if (acl == null)
|
if (acl == null)
|
||||||
{
|
{
|
||||||
@@ -426,12 +435,8 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// if(acl.equals(mergeFrom))
|
|
||||||
// {
|
|
||||||
// setFixedAcls(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false);
|
|
||||||
// }
|
|
||||||
// Still has old shared ACL or already replaced
|
// Still has old shared ACL or already replaced
|
||||||
if(acl.equals(sharedAclToReplace) || acl.equals(mergeFrom))
|
if(acl.equals(sharedAclToReplace) || acl.equals(mergeFrom) || acl.equals(currentAcl))
|
||||||
{
|
{
|
||||||
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren);
|
propagateOnChildren = setFixAclPending(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false, asyncCall, propagateOnChildren);
|
||||||
}
|
}
|
||||||
@@ -457,6 +462,21 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// By doing an eager update of the direct children we canot see if another thread has changed the ACL
|
||||||
|
// between the time we get the child nodes and we update them. By updating the direct children last it is
|
||||||
|
// possible to verify if any child has changed meanwhile.
|
||||||
|
if(children.size() > 0)
|
||||||
|
{
|
||||||
|
nodeDAO.setPrimaryChildrenSharedAclId(nodeId, sharedAclToReplace, mergeFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When this is not executed triggered by the job, but a move or copy operation occures on a pending
|
||||||
|
// node, we don't want to apply the OLD ACL that was pending
|
||||||
|
if(nodeDAO.hasNodeAspect(nodeId, ContentModel.ASPECT_PENDING_FIX_ACL))
|
||||||
|
{
|
||||||
|
removePendingAclAspect(nodeId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,14 +529,23 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
}
|
}
|
||||||
// set ASPECT_PENDING_FIX_ACL aspect on node to be later on processed with FixedAclUpdater amd switch flag
|
// set ASPECT_PENDING_FIX_ACL aspect on node to be later on processed with FixedAclUpdater amd switch flag
|
||||||
// FIXED_ACL_ASYNC_REQUIRED_KEY
|
// FIXED_ACL_ASYNC_REQUIRED_KEY
|
||||||
addFixedAclPendingAspect(nodeId, sharedAclToReplace, inheritFrom);
|
addFixedAclPendingAspect(nodeId, sharedAclToReplace, inheritFrom, mergeFrom);
|
||||||
AlfrescoTransactionSupport.bindResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY, true);
|
AlfrescoTransactionSupport.bindResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY, true);
|
||||||
// stop propagating on children nodes
|
// stop propagating on children nodes
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFixedAclPendingAspect(Long nodeId, Long sharedAclToReplace, Long inheritFrom)
|
private void addFixedAclPendingAspect(Long nodeId, Long sharedAclToReplace, Long inheritFrom, Long mergeFrom)
|
||||||
{
|
{
|
||||||
|
//If the node already has the pending ACL aspect, just update the new inheritFrom value
|
||||||
|
if (nodeDAO.hasNodeAspect(nodeId, ContentModel.ASPECT_PENDING_FIX_ACL))
|
||||||
|
{
|
||||||
|
Map<QName, Serializable> pendingAclProperties = new HashMap<>();
|
||||||
|
pendingAclProperties.put(ContentModel.PROP_INHERIT_FROM_ACL, inheritFrom);
|
||||||
|
nodeDAO.addNodeProperties(nodeId, pendingAclProperties);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Set<QName> aspect = new HashSet<>();
|
Set<QName> aspect = new HashSet<>();
|
||||||
aspect.add(ContentModel.ASPECT_PENDING_FIX_ACL);
|
aspect.add(ContentModel.ASPECT_PENDING_FIX_ACL);
|
||||||
nodeDAO.addNodeAspects(nodeId, aspect);
|
nodeDAO.addNodeAspects(nodeId, aspect);
|
||||||
@@ -530,6 +559,17 @@ public class ADMAccessControlListDAO implements AccessControlListDAO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removePendingAclAspect(Long nodeId)
|
||||||
|
{
|
||||||
|
Set<QName> aspects = new HashSet<>(1);
|
||||||
|
aspects.add(ContentModel.ASPECT_PENDING_FIX_ACL);
|
||||||
|
Set<QName> pendingFixAclProperties = new HashSet<>();
|
||||||
|
pendingFixAclProperties.add(ContentModel.PROP_SHARED_ACL_TO_REPLACE);
|
||||||
|
pendingFixAclProperties.add(ContentModel.PROP_INHERIT_FROM_ACL);
|
||||||
|
nodeDAO.removeNodeAspects(nodeId, aspects);
|
||||||
|
nodeDAO.removeNodeProperties(nodeId, pendingFixAclProperties);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
@@ -106,4 +106,6 @@ public interface AccessControlListDAO
|
|||||||
public void updateInheritance(Long childNodeId, Long oldParentAclId, Long newParentAclId);
|
public void updateInheritance(Long childNodeId, Long oldParentAclId, Long newParentAclId);
|
||||||
|
|
||||||
public void setFixedAcls(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List<AclChange> changes, boolean set);
|
public void setFixedAcls(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List<AclChange> changes, boolean set);
|
||||||
|
|
||||||
|
public void removePendingAclAspect(Long nodeId);
|
||||||
}
|
}
|
||||||
|
@@ -53,7 +53,6 @@ import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
|||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.repo.transaction.TransactionListenerAdapter;
|
import org.alfresco.repo.transaction.TransactionListenerAdapter;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef.Status;
|
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.service.namespace.NamespaceService;
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
@@ -151,7 +150,8 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
|||||||
|
|
||||||
public void init()
|
public void init()
|
||||||
{
|
{
|
||||||
onInheritPermissionsDisabledDelegate = policyComponent.registerClassPolicy(PermissionServicePolicies.OnInheritPermissionsDisabled.class);
|
onInheritPermissionsDisabledDelegate = policyComponent
|
||||||
|
.registerClassPolicy(PermissionServicePolicies.OnInheritPermissionsDisabled.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class GetNodesWithAspects
|
private class GetNodesWithAspects
|
||||||
@@ -264,35 +264,34 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
|||||||
{
|
{
|
||||||
log.debug(String.format("Processing node %s", nodeRef));
|
log.debug(String.format("Processing node %s", nodeRef));
|
||||||
}
|
}
|
||||||
|
|
||||||
final Long nodeId = nodeDAO.getNodePair(nodeRef).getFirst();
|
final Long nodeId = nodeDAO.getNodePair(nodeRef).getFirst();
|
||||||
|
|
||||||
// MNT-22009 - If node was deleted and in archive store, remove the aspect and properties and do not
|
// MNT-22009 - If node was deleted and in archive store, remove the aspect and properties and do not
|
||||||
// process
|
// process
|
||||||
if (nodeRef.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE))
|
if (nodeRef.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE))
|
||||||
{
|
{
|
||||||
nodeDAO.removeNodeAspects(nodeId, aspects);
|
accessControlListDAO.removePendingAclAspect(nodeId);
|
||||||
nodeDAO.removeNodeProperties(nodeId, PENDING_FIX_ACL_ASPECT_PROPS);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve acl properties from node
|
// retrieve acl properties from node
|
||||||
Long inheritFrom = (Long) nodeDAO.getNodeProperty(nodeId,
|
Long inheritFrom = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_INHERIT_FROM_ACL);
|
||||||
ContentModel.PROP_INHERIT_FROM_ACL);
|
Long sharedAclToReplace = (Long) nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_SHARED_ACL_TO_REPLACE);
|
||||||
Long sharedAclToReplace = (Long) nodeDAO.getNodeProperty(nodeId,
|
|
||||||
ContentModel.PROP_SHARED_ACL_TO_REPLACE);
|
|
||||||
|
|
||||||
// set inheritance using retrieved prop
|
// set inheritance using retrieved prop
|
||||||
accessControlListDAO.setInheritanceForChildren(nodeRef, inheritFrom, sharedAclToReplace,
|
accessControlListDAO.setInheritanceForChildren(nodeRef, inheritFrom, sharedAclToReplace, true);
|
||||||
true);
|
|
||||||
|
|
||||||
nodeDAO.removeNodeAspects(nodeId, aspects);
|
// Remove aspect
|
||||||
nodeDAO.removeNodeProperties(nodeId, PENDING_FIX_ACL_ASPECT_PROPS);
|
accessControlListDAO.removePendingAclAspect(nodeId);
|
||||||
|
|
||||||
if (!policyIgnoreUtil.ignorePolicy(nodeRef))
|
if (!policyIgnoreUtil.ignorePolicy(nodeRef))
|
||||||
{
|
{
|
||||||
boolean transformedToAsyncOperation = toBoolean((Boolean) AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY));
|
boolean transformedToAsyncOperation = toBoolean(
|
||||||
|
(Boolean) AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY));
|
||||||
|
|
||||||
OnInheritPermissionsDisabled onInheritPermissionsDisabledPolicy = onInheritPermissionsDisabledDelegate.get(ContentModel.TYPE_BASE);
|
OnInheritPermissionsDisabled onInheritPermissionsDisabledPolicy = onInheritPermissionsDisabledDelegate
|
||||||
|
.get(ContentModel.TYPE_BASE);
|
||||||
onInheritPermissionsDisabledPolicy.onInheritPermissionsDisabled(nodeRef, transformedToAsyncOperation);
|
onInheritPermissionsDisabledPolicy.onInheritPermissionsDisabled(nodeRef, transformedToAsyncOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,12 +405,8 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
|||||||
|
|
||||||
AclWorkProvider provider = new AclWorkProvider();
|
AclWorkProvider provider = new AclWorkProvider();
|
||||||
AclWorker worker = new AclWorker();
|
AclWorker worker = new AclWorker();
|
||||||
BatchProcessor<NodeRef> bp = new BatchProcessor<>(
|
BatchProcessor<NodeRef> bp = new BatchProcessor<>("FixedAclUpdater",
|
||||||
"FixedAclUpdater",
|
transactionService.getRetryingTransactionHelper(), provider, numThreads, maxItemBatchSize, applicationContext,
|
||||||
transactionService.getRetryingTransactionHelper(),
|
|
||||||
provider,
|
|
||||||
numThreads, maxItemBatchSize,
|
|
||||||
applicationContext,
|
|
||||||
log, 100);
|
log, 100);
|
||||||
int count = bp.process(worker, true);
|
int count = bp.process(worker, true);
|
||||||
return count;
|
return count;
|
||||||
@@ -424,7 +419,7 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
jobLockRefreshCallback.isActive.set(false);
|
jobLockRefreshCallback.isActive.set(false);
|
||||||
if(lockToken != null)
|
if (lockToken != null)
|
||||||
{
|
{
|
||||||
jobLockService.releaseLock(lockToken, lockQName);
|
jobLockService.releaseLock(lockToken, lockQName);
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user