fix for CLOUD-2150: Trashcan for network admins only shows their deleted content.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@57583 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jamal Kaabi-Mofrad
2013-11-04 10:10:02 +00:00
parent 6a5e3923a7
commit fa8910384a
5 changed files with 139 additions and 71 deletions

View File

@@ -127,6 +127,15 @@
<property name="cannedQueryRegistry"> <property name="cannedQueryRegistry">
<ref bean="archivedNodesCannedQueryRegistry"/> <ref bean="archivedNodesCannedQueryRegistry"/>
</property> </property>
<property name="authorityService">
<ref bean="authorityService"/>
</property>
<property name="tenantService">
<ref bean="tenantService"/>
</property>
<property name="userNamesAreCaseSensitive">
<value>${user.name.caseSensitive}</value>
</property>
</bean> </bean>
<!-- Archived Nodes --> <!-- Archived Nodes -->
@@ -135,10 +144,8 @@
</bean> </bean>
<bean name="archivedNodesCannedQueryFactory" class="org.alfresco.repo.node.archive.GetArchivedNodesCannedQueryFactory"> <bean name="archivedNodesCannedQueryFactory" class="org.alfresco.repo.node.archive.GetArchivedNodesCannedQueryFactory">
<property name="registry" ref="archivedNodesCannedQueryRegistry"/> <property name="registry" ref="archivedNodesCannedQueryRegistry"/>
<property name="authorityService" ref="authorityService"/>
<property name="tenantService" ref="tenantService"/> <property name="tenantService" ref="tenantService"/>
<property name="nodeDAO" ref="nodeDAO"/> <property name="nodeDAO" ref="nodeDAO"/>
<property name="nodeService" ref="nodeService"/>
<property name="qnameDAO" ref="qnameDAO"/> <property name="qnameDAO" ref="qnameDAO"/>
<property name="cannedQueryDAO" ref="cannedQueryDAO"/> <property name="cannedQueryDAO" ref="cannedQueryDAO"/>
<property name="methodSecurity" ref="ArchivedNodes_security_listArchivedNodes"/> <property name="methodSecurity" ref="ArchivedNodes_security_listArchivedNodes"/>

View File

@@ -19,23 +19,14 @@
package org.alfresco.repo.node.archive; package org.alfresco.repo.node.archive;
import java.util.Collections;
import java.util.List;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQuery; import org.alfresco.query.CannedQuery;
import org.alfresco.query.CannedQueryPageDetails; import org.alfresco.query.CannedQueryPageDetails;
import org.alfresco.query.CannedQueryParameters; import org.alfresco.query.CannedQueryParameters;
import org.alfresco.query.PagingRequest; import org.alfresco.query.PagingRequest;
import org.alfresco.repo.query.AbstractQNameAwareCannedQueryFactory; import org.alfresco.repo.query.AbstractQNameAwareCannedQueryFactory;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.namespace.QName;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
/** /**
@@ -46,19 +37,6 @@ import org.alfresco.util.ParameterCheck;
*/ */
public class GetArchivedNodesCannedQueryFactory extends AbstractQNameAwareCannedQueryFactory<ArchivedNodeEntity> public class GetArchivedNodesCannedQueryFactory extends AbstractQNameAwareCannedQueryFactory<ArchivedNodeEntity>
{ {
private AuthorityService authorityService;
protected NodeService nodeService;
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
@Override @Override
public CannedQuery<ArchivedNodeEntity> getCannedQuery(CannedQueryParameters parameters) public CannedQuery<ArchivedNodeEntity> getCannedQuery(CannedQueryParameters parameters)
{ {
@@ -74,19 +52,19 @@ public class GetArchivedNodesCannedQueryFactory extends AbstractQNameAwareCanned
* @param sortOrderAscending * @param sortOrderAscending
* @return an implementation that will execute the query * @return an implementation that will execute the query
*/ */
public CannedQuery<ArchivedNodeEntity> getCannedQuery(NodeRef archiveStoreRootNodeRef, public CannedQuery<ArchivedNodeEntity> getCannedQuery(NodeRef archiveStoreRootNodeRef, QName assocTypeQName,
String filter, boolean filterIgnoreCase, PagingRequest pagingRequest, String filter, boolean filterIgnoreCase, PagingRequest pagingRequest,
boolean sortOrderAscending) boolean sortOrderAscending)
{ {
ParameterCheck.mandatory("archiveStoreRootNodeRef", archiveStoreRootNodeRef);
ParameterCheck.mandatory("pagingRequest", pagingRequest); ParameterCheck.mandatory("pagingRequest", pagingRequest);
Long nodeId = (archiveStoreRootNodeRef == null) ? -1 : getNodeId(archiveStoreRootNodeRef);
Long qnameId = (assocTypeQName == null) ? -1 : getQNameId(assocTypeQName);
int requestTotalCountMax = pagingRequest.getRequestTotalCountMax(); int requestTotalCountMax = pagingRequest.getRequestTotalCountMax();
Pair<Long, Long> nodeIdAssocTypeIdPair = getNodeIdAssocTypeIdPair(archiveStoreRootNodeRef); GetArchivedNodesCannedQueryParams paramBean = new GetArchivedNodesCannedQueryParams(nodeId,
GetArchivedNodesCannedQueryParams paramBean = new GetArchivedNodesCannedQueryParams( qnameId, filter, filterIgnoreCase, getQNameId(ContentModel.PROP_NAME),
nodeIdAssocTypeIdPair.getFirst(), nodeIdAssocTypeIdPair.getSecond(), filter, sortOrderAscending);
filterIgnoreCase, getQNameId(ContentModel.PROP_NAME), sortOrderAscending);
// page details // page details
CannedQueryPageDetails cqpd = new CannedQueryPageDetails(pagingRequest.getSkipCount(), CannedQueryPageDetails cqpd = new CannedQueryPageDetails(pagingRequest.getSkipCount(),
@@ -100,39 +78,4 @@ public class GetArchivedNodesCannedQueryFactory extends AbstractQNameAwareCanned
// return canned query instance // return canned query instance
return getCannedQuery(params); return getCannedQuery(params);
} }
private Pair<Long, Long> getNodeIdAssocTypeIdPair(NodeRef archiveStoreRootNodeRef)
{
String userID = AuthenticationUtil.getFullyAuthenticatedUser();
if (userID == null)
{
throw new AuthenticationException("Failed to authenticate. Current user, ", new Object[] { userID });
}
if (archiveStoreRootNodeRef == null || !nodeService.exists(archiveStoreRootNodeRef))
{
throw new InvalidNodeRefException("Invalid archive store root node Ref.",
archiveStoreRootNodeRef);
}
if (authorityService.isAdminAuthority(userID))
{
return new Pair<Long, Long>(getNodeId(archiveStoreRootNodeRef),
getQNameId(ContentModel.ASSOC_CHILDREN));
}
else
{
List<ChildAssociationRef> list = nodeService.getChildrenByName(archiveStoreRootNodeRef,
ContentModel.ASSOC_ARCHIVE_USER_LINK, Collections.singletonList(userID));
// Empty list means that the current user hasn't deleted anything yet.
if (list.isEmpty())
{
return new Pair<Long, Long>(-1L, -1L);
}
NodeRef userArchive = list.get(0).getChildRef();
return new Pair<Long, Long>(getNodeId(userArchive),
getQNameId(ContentModel.ASSOC_ARCHIVED_LINK));
}
}
} }

View File

@@ -188,4 +188,13 @@ public interface NodeArchiveService
* @since 4.2 * @since 4.2
*/ */
public PagingResults<NodeRef> listArchivedNodes(ArchivedNodesCannedQueryBuilder cannedQueryBuilder); public PagingResults<NodeRef> listArchivedNodes(ArchivedNodesCannedQueryBuilder cannedQueryBuilder);
/**
* Check if the current user has authority to access the archived node.
*
* @param nodeRef
* @return true if the currently authenticated user has authority to access
* the archived node, otherwise false.
*/
public boolean hasFullAccess(NodeRef nodeRef);
} }

View File

@@ -39,6 +39,7 @@ import org.alfresco.repo.node.archive.RestoreNodeReport.RestoreStatus;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
@@ -48,6 +49,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
@@ -75,11 +77,14 @@ public class NodeArchiveServiceImpl implements NodeArchiveService
private static Log logger = LogFactory.getLog(NodeArchiveServiceImpl.class); private static Log logger = LogFactory.getLog(NodeArchiveServiceImpl.class);
private NodeService nodeService; protected NodeService nodeService;
private PermissionService permissionService; private PermissionService permissionService;
private TransactionService transactionService; private TransactionService transactionService;
private JobLockService jobLockService; private JobLockService jobLockService;
private AuthorityService authorityService;
private NamedObjectRegistry<CannedQueryFactory<ArchivedNodeEntity>> cannedQueryRegistry; private NamedObjectRegistry<CannedQueryFactory<ArchivedNodeEntity>> cannedQueryRegistry;
private TenantService tenantService;
private boolean userNamesAreCaseSensitive = false;
public void setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
{ {
@@ -106,10 +111,25 @@ public class NodeArchiveServiceImpl implements NodeArchiveService
this.jobLockService = jobLockService; this.jobLockService = jobLockService;
} }
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
public void setCannedQueryRegistry(NamedObjectRegistry<CannedQueryFactory<ArchivedNodeEntity>> cannedQueryRegistry) public void setCannedQueryRegistry(NamedObjectRegistry<CannedQueryFactory<ArchivedNodeEntity>> cannedQueryRegistry)
{ {
this.cannedQueryRegistry = cannedQueryRegistry; this.cannedQueryRegistry = cannedQueryRegistry;
} }
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setUserNamesAreCaseSensitive(boolean userNamesAreCaseSensitive)
{
this.userNamesAreCaseSensitive = userNamesAreCaseSensitive;
}
public NodeRef getArchivedNode(NodeRef originalNodeRef) public NodeRef getArchivedNode(NodeRef originalNodeRef)
{ {
@@ -566,8 +586,9 @@ public class NodeArchiveServiceImpl implements NodeArchiveService
GetArchivedNodesCannedQueryFactory getArchivedNodesCannedQueryFactory = (GetArchivedNodesCannedQueryFactory) cannedQueryRegistry GetArchivedNodesCannedQueryFactory getArchivedNodesCannedQueryFactory = (GetArchivedNodesCannedQueryFactory) cannedQueryRegistry
.getNamedObject(CANNED_QUERY_ARCHIVED_NODES_LIST); .getNamedObject(CANNED_QUERY_ARCHIVED_NODES_LIST);
Pair<NodeRef, QName> archiveNodeRefAssocTypePair = getArchiveNodeRefAssocTypePair(cannedQueryBuilder.getArchiveRootNodeRef());
GetArchivedNodesCannedQuery cq = (GetArchivedNodesCannedQuery) getArchivedNodesCannedQueryFactory GetArchivedNodesCannedQuery cq = (GetArchivedNodesCannedQuery) getArchivedNodesCannedQueryFactory
.getCannedQuery(cannedQueryBuilder.getArchiveRootNodeRef(), .getCannedQuery(archiveNodeRefAssocTypePair.getFirst(), archiveNodeRefAssocTypePair.getSecond(),
cannedQueryBuilder.getFilter(), cannedQueryBuilder.getFilter(),
cannedQueryBuilder.isFilterIgnoreCase(), cannedQueryBuilder.isFilterIgnoreCase(),
cannedQueryBuilder.getPagingRequest(), cannedQueryBuilder.getPagingRequest(),
@@ -651,4 +672,80 @@ public class NodeArchiveServiceImpl implements NodeArchiveService
} }
}; };
} }
/**
* {@inheritDoc}
*/
public boolean hasFullAccess(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
String currentUser = getCurrentUser();
if (hasAdminAccess(currentUser))
{
return true;
}
else
{
String archivedBy = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_ARCHIVED_BY);
if(!userNamesAreCaseSensitive && archivedBy != null)
{
archivedBy = archivedBy.toLowerCase();
}
return currentUser.equals(archivedBy);
}
}
protected boolean hasAdminAccess(String userID)
{
return authorityService.isAdminAuthority(userID);
}
private Pair<NodeRef, QName> getArchiveNodeRefAssocTypePair(final NodeRef archiveStoreRootNodeRef)
{
String currentUser = getCurrentUser();
if (archiveStoreRootNodeRef == null || !nodeService.exists(archiveStoreRootNodeRef))
{
throw new InvalidNodeRefException("Invalid archive store root node Ref.",
archiveStoreRootNodeRef);
}
if (hasAdminAccess(currentUser))
{
return new Pair<NodeRef, QName>(archiveStoreRootNodeRef, ContentModel.ASSOC_CHILDREN);
}
else
{
List<ChildAssociationRef> list = nodeService.getChildrenByName(archiveStoreRootNodeRef,
ContentModel.ASSOC_ARCHIVE_USER_LINK,
Collections.singletonList(currentUser));
// Empty list means that the current user hasn't deleted anything yet.
if (list.isEmpty())
{
return new Pair<NodeRef, QName>(null, null);
}
NodeRef userArchive = list.get(0).getChildRef();
return new Pair<NodeRef, QName>(userArchive, ContentModel.ASSOC_ARCHIVED_LINK);
}
}
private String getCurrentUser()
{
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
if (currentUser == null)
{
throw new AccessDeniedException("No authenticated user; cannot get archived nodes.");
}
if (!userNamesAreCaseSensitive
&& !AuthenticationUtil.getSystemUserName().equals(
tenantService.getBaseNameUser(currentUser)))
{
// user names are not case-sensitive
currentUser = currentUser.toLowerCase();
}
return currentUser;
}
} }

View File

@@ -953,13 +953,13 @@ public class ArchiveAndRestoreTest extends TestCase
this.archiveStoreRootNodeRef, paging).filterIgnoreCase(true).build(); this.archiveStoreRootNodeRef, paging).filterIgnoreCase(true).build();
// Query the DB // Query the DB
PagingResults<NodeRef> result = nodeArchiveService.listArchivedNodes(queryBuilder); PagingResults<NodeRef> result = runListArchivedNodesAsAdmin(queryBuilder);
assertEquals("USER_B hasn't deleted anything yet.", 0, result.getPage().size()); assertEquals("USER_B hasn't deleted anything yet.", 0, result.getPage().size());
// USER_B deletes "bb" // USER_B deletes "bb"
nodeService.deleteNode(bb); nodeService.deleteNode(bb);
result = nodeArchiveService.listArchivedNodes(queryBuilder); result = runListArchivedNodesAsAdmin(queryBuilder);
assertEquals("USER_B deleted only 1 item.", 1, result.getPage().size()); assertEquals("USER_B deleted only 1 item.", 1, result.getPage().size());
AuthenticationUtil.setFullyAuthenticatedUser(USER_A); AuthenticationUtil.setFullyAuthenticatedUser(USER_A);
@@ -971,7 +971,7 @@ public class ArchiveAndRestoreTest extends TestCase
this.archiveStoreRootNodeRef, paging) this.archiveStoreRootNodeRef, paging)
.filterIgnoreCase(true).build(); .filterIgnoreCase(true).build();
result = nodeArchiveService.listArchivedNodes(queryBuilder); result = runListArchivedNodesAsAdmin(queryBuilder);
assertEquals("USER_A deleted only 1 item.", 1, result.getPage().size()); assertEquals("USER_A deleted only 1 item.", 1, result.getPage().size());
assertEquals(QNAME_AA.getLocalName(), assertEquals(QNAME_AA.getLocalName(),
nodeService.getProperty(result.getPage().get(0), ContentModel.PROP_NAME)); nodeService.getProperty(result.getPage().get(0), ContentModel.PROP_NAME));
@@ -988,6 +988,18 @@ public class ArchiveAndRestoreTest extends TestCase
assertEquals("Admin can retrieve all users' deleted nodes.", 2, result.getPage().size()); assertEquals("Admin can retrieve all users' deleted nodes.", 2, result.getPage().size());
} }
private PagingResults<NodeRef> runListArchivedNodesAsAdmin(final ArchivedNodesCannedQueryBuilder queryBuilder)
{
return AuthenticationUtil.runAs(new RunAsWork<PagingResults<NodeRef>>()
{
@Override
public PagingResults<NodeRef> doWork() throws Exception
{
return nodeArchiveService.listArchivedNodes(queryBuilder);
}
}, AuthenticationUtil.getAdminUserName());
}
/** /**
* Test listArchivedNodes sorted by ARCHIVED_DATE (DESC). * Test listArchivedNodes sorted by ARCHIVED_DATE (DESC).
*/ */