diff --git a/config/alfresco/node-services-context.xml b/config/alfresco/node-services-context.xml index 0ed7523bdb..9c58460a93 100644 --- a/config/alfresco/node-services-context.xml +++ b/config/alfresco/node-services-context.xml @@ -127,6 +127,15 @@ + + + + + + + + ${user.name.caseSensitive} + @@ -135,10 +144,8 @@ - - diff --git a/source/java/org/alfresco/repo/node/archive/GetArchivedNodesCannedQueryFactory.java b/source/java/org/alfresco/repo/node/archive/GetArchivedNodesCannedQueryFactory.java index 5d011fb140..1fe1d2452a 100644 --- a/source/java/org/alfresco/repo/node/archive/GetArchivedNodesCannedQueryFactory.java +++ b/source/java/org/alfresco/repo/node/archive/GetArchivedNodesCannedQueryFactory.java @@ -19,23 +19,14 @@ package org.alfresco.repo.node.archive; -import java.util.Collections; -import java.util.List; - import org.alfresco.model.ContentModel; import org.alfresco.query.CannedQuery; import org.alfresco.query.CannedQueryPageDetails; import org.alfresco.query.CannedQueryParameters; import org.alfresco.query.PagingRequest; 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.NodeService; -import org.alfresco.service.cmr.security.AuthorityService; -import org.alfresco.util.Pair; +import org.alfresco.service.namespace.QName; import org.alfresco.util.ParameterCheck; /** @@ -46,19 +37,6 @@ import org.alfresco.util.ParameterCheck; */ public class GetArchivedNodesCannedQueryFactory extends AbstractQNameAwareCannedQueryFactory { - private AuthorityService authorityService; - protected NodeService nodeService; - - public void setAuthorityService(AuthorityService authorityService) - { - this.authorityService = authorityService; - } - - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - @Override public CannedQuery getCannedQuery(CannedQueryParameters parameters) { @@ -74,19 +52,19 @@ public class GetArchivedNodesCannedQueryFactory extends AbstractQNameAwareCanned * @param sortOrderAscending * @return an implementation that will execute the query */ - public CannedQuery getCannedQuery(NodeRef archiveStoreRootNodeRef, + public CannedQuery getCannedQuery(NodeRef archiveStoreRootNodeRef, QName assocTypeQName, String filter, boolean filterIgnoreCase, PagingRequest pagingRequest, boolean sortOrderAscending) { - ParameterCheck.mandatory("archiveStoreRootNodeRef", archiveStoreRootNodeRef); ParameterCheck.mandatory("pagingRequest", pagingRequest); + Long nodeId = (archiveStoreRootNodeRef == null) ? -1 : getNodeId(archiveStoreRootNodeRef); + Long qnameId = (assocTypeQName == null) ? -1 : getQNameId(assocTypeQName); int requestTotalCountMax = pagingRequest.getRequestTotalCountMax(); - Pair nodeIdAssocTypeIdPair = getNodeIdAssocTypeIdPair(archiveStoreRootNodeRef); - GetArchivedNodesCannedQueryParams paramBean = new GetArchivedNodesCannedQueryParams( - nodeIdAssocTypeIdPair.getFirst(), nodeIdAssocTypeIdPair.getSecond(), filter, - filterIgnoreCase, getQNameId(ContentModel.PROP_NAME), sortOrderAscending); + GetArchivedNodesCannedQueryParams paramBean = new GetArchivedNodesCannedQueryParams(nodeId, + qnameId, filter, filterIgnoreCase, getQNameId(ContentModel.PROP_NAME), + sortOrderAscending); // page details CannedQueryPageDetails cqpd = new CannedQueryPageDetails(pagingRequest.getSkipCount(), @@ -100,39 +78,4 @@ public class GetArchivedNodesCannedQueryFactory extends AbstractQNameAwareCanned // return canned query instance return getCannedQuery(params); } - - private Pair 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(getNodeId(archiveStoreRootNodeRef), - getQNameId(ContentModel.ASSOC_CHILDREN)); - } - else - { - List 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(-1L, -1L); - } - NodeRef userArchive = list.get(0).getChildRef(); - return new Pair(getNodeId(userArchive), - getQNameId(ContentModel.ASSOC_ARCHIVED_LINK)); - } - } } diff --git a/source/java/org/alfresco/repo/node/archive/NodeArchiveService.java b/source/java/org/alfresco/repo/node/archive/NodeArchiveService.java index c1ee932df3..5f2177f492 100644 --- a/source/java/org/alfresco/repo/node/archive/NodeArchiveService.java +++ b/source/java/org/alfresco/repo/node/archive/NodeArchiveService.java @@ -188,4 +188,13 @@ public interface NodeArchiveService * @since 4.2 */ public PagingResults 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); } diff --git a/source/java/org/alfresco/repo/node/archive/NodeArchiveServiceImpl.java b/source/java/org/alfresco/repo/node/archive/NodeArchiveServiceImpl.java index 437ad11e7d..db40799eeb 100644 --- a/source/java/org/alfresco/repo/node/archive/NodeArchiveServiceImpl.java +++ b/source/java/org/alfresco/repo/node/archive/NodeArchiveServiceImpl.java @@ -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.RunAsWork; 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.RetryingTransactionCallback; 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.StoreRef; 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.namespace.NamespaceService; import org.alfresco.service.namespace.QName; @@ -75,11 +77,14 @@ public class NodeArchiveServiceImpl implements NodeArchiveService private static Log logger = LogFactory.getLog(NodeArchiveServiceImpl.class); - private NodeService nodeService; + protected NodeService nodeService; private PermissionService permissionService; private TransactionService transactionService; private JobLockService jobLockService; + private AuthorityService authorityService; private NamedObjectRegistry> cannedQueryRegistry; + private TenantService tenantService; + private boolean userNamesAreCaseSensitive = false; public void setNodeService(NodeService nodeService) { @@ -106,10 +111,25 @@ public class NodeArchiveServiceImpl implements NodeArchiveService this.jobLockService = jobLockService; } + public void setAuthorityService(AuthorityService authorityService) + { + this.authorityService = authorityService; + } + public void setCannedQueryRegistry(NamedObjectRegistry> 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) { @@ -566,8 +586,9 @@ public class NodeArchiveServiceImpl implements NodeArchiveService GetArchivedNodesCannedQueryFactory getArchivedNodesCannedQueryFactory = (GetArchivedNodesCannedQueryFactory) cannedQueryRegistry .getNamedObject(CANNED_QUERY_ARCHIVED_NODES_LIST); + Pair archiveNodeRefAssocTypePair = getArchiveNodeRefAssocTypePair(cannedQueryBuilder.getArchiveRootNodeRef()); GetArchivedNodesCannedQuery cq = (GetArchivedNodesCannedQuery) getArchivedNodesCannedQueryFactory - .getCannedQuery(cannedQueryBuilder.getArchiveRootNodeRef(), + .getCannedQuery(archiveNodeRefAssocTypePair.getFirst(), archiveNodeRefAssocTypePair.getSecond(), cannedQueryBuilder.getFilter(), cannedQueryBuilder.isFilterIgnoreCase(), 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 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(archiveStoreRootNodeRef, ContentModel.ASSOC_CHILDREN); + } + else + { + List 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(null, null); + } + NodeRef userArchive = list.get(0).getChildRef(); + return new Pair(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; + } } diff --git a/source/test-java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java b/source/test-java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java index ed0ce407ff..3bf9acbb22 100644 --- a/source/test-java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java +++ b/source/test-java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java @@ -953,13 +953,13 @@ public class ArchiveAndRestoreTest extends TestCase this.archiveStoreRootNodeRef, paging).filterIgnoreCase(true).build(); // Query the DB - PagingResults result = nodeArchiveService.listArchivedNodes(queryBuilder); + PagingResults result = runListArchivedNodesAsAdmin(queryBuilder); assertEquals("USER_B hasn't deleted anything yet.", 0, result.getPage().size()); // USER_B deletes "bb" nodeService.deleteNode(bb); - result = nodeArchiveService.listArchivedNodes(queryBuilder); + result = runListArchivedNodesAsAdmin(queryBuilder); assertEquals("USER_B deleted only 1 item.", 1, result.getPage().size()); AuthenticationUtil.setFullyAuthenticatedUser(USER_A); @@ -971,7 +971,7 @@ public class ArchiveAndRestoreTest extends TestCase this.archiveStoreRootNodeRef, paging) .filterIgnoreCase(true).build(); - result = nodeArchiveService.listArchivedNodes(queryBuilder); + result = runListArchivedNodesAsAdmin(queryBuilder); assertEquals("USER_A deleted only 1 item.", 1, result.getPage().size()); assertEquals(QNAME_AA.getLocalName(), 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()); } + private PagingResults runListArchivedNodesAsAdmin(final ArchivedNodesCannedQueryBuilder queryBuilder) + { + return AuthenticationUtil.runAs(new RunAsWork>() + { + @Override + public PagingResults doWork() throws Exception + { + return nodeArchiveService.listArchivedNodes(queryBuilder); + } + }, AuthenticationUtil.getAdminUserName()); + } + /** * Test listArchivedNodes sorted by ARCHIVED_DATE (DESC). */