mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Bugfix/APPS-766 classification children job not picking rm types (#272)
* Now handling System reading * Address changes requested in PR #272
This commit is contained in:
@@ -298,8 +298,8 @@ public class PagingLuceneResultSet implements ResultSet, Serializable
|
||||
return wrapped.getSpellCheckResult();
|
||||
}
|
||||
|
||||
public void setTrimmedResultSet(boolean b)
|
||||
public void setTrimmedResultSet(boolean value)
|
||||
{
|
||||
this.trimmedResultSet = true;
|
||||
this.trimmedResultSet = value;
|
||||
}
|
||||
}
|
||||
|
@@ -27,7 +27,6 @@ package org.alfresco.repo.search.impl.querymodel.impl.db;
|
||||
|
||||
import static org.alfresco.repo.domain.node.AbstractNodeDAOImpl.CACHE_REGION_NODES;
|
||||
import static org.alfresco.repo.search.impl.querymodel.impl.db.DBStats.aclOwnerStopWatch;
|
||||
import static org.alfresco.repo.search.impl.querymodel.impl.db.DBStats.aclReadStopWatch;
|
||||
import static org.alfresco.repo.search.impl.querymodel.impl.db.DBStats.handlerStopWatch;
|
||||
import static org.alfresco.repo.search.impl.querymodel.impl.db.DBStats.resetStopwatches;
|
||||
|
||||
@@ -113,7 +112,7 @@ public class DBQueryEngine implements QueryEngine
|
||||
|
||||
private OptionalPatchApplicationCheckBootstrapBean metadataIndexCheck2;
|
||||
|
||||
private PermissionService permissionService;
|
||||
PermissionService permissionService;
|
||||
|
||||
private int maxPermissionChecks;
|
||||
|
||||
@@ -125,7 +124,7 @@ public class DBQueryEngine implements QueryEngine
|
||||
|
||||
private SimpleCache<NodeVersionKey, Set<QName>> aspectsCache;
|
||||
|
||||
private AclCrudDAO aclCrudDAO;
|
||||
AclCrudDAO aclCrudDAO;
|
||||
|
||||
public void setAclCrudDAO(AclCrudDAO aclCrudDAO)
|
||||
{
|
||||
@@ -331,7 +330,8 @@ public class DBQueryEngine implements QueryEngine
|
||||
|
||||
NodePermissionAssessor createAssessor(QueryOptions options)
|
||||
{
|
||||
NodePermissionAssessor permissionAssessor = new NodePermissionAssessor();
|
||||
Authority authority = aclCrudDAO.getAuthority(AuthenticationUtil.getRunAsUser());
|
||||
NodePermissionAssessor permissionAssessor = new NodePermissionAssessor(nodeService, permissionService, authority, nodesCache);
|
||||
int maxPermsChecks = options.getMaxPermissionChecks() < 0 ? maxPermissionChecks : options.getMaxPermissionChecks();
|
||||
long maxPermCheckTimeMillis = options.getMaxPermissionCheckTimeMillis() < 0
|
||||
? maxPermissionCheckTimeMillis
|
||||
@@ -485,104 +485,6 @@ public class DBQueryEngine implements QueryEngine
|
||||
return new DBQueryModelFactory();
|
||||
}
|
||||
|
||||
public class NodePermissionAssessor
|
||||
{
|
||||
private final boolean isAdminReading;
|
||||
|
||||
private final Authority authority;
|
||||
|
||||
private final Map<Long, Boolean> aclReadCache = new HashMap<>();
|
||||
|
||||
private int checksPerformed;
|
||||
|
||||
private long startTime;
|
||||
|
||||
private int maxPermissionChecks;
|
||||
|
||||
private long maxPermissionCheckTimeMillis;
|
||||
|
||||
public NodePermissionAssessor()
|
||||
{
|
||||
this.checksPerformed = 0;
|
||||
this.maxPermissionChecks = Integer.MAX_VALUE;
|
||||
this.maxPermissionCheckTimeMillis = Long.MAX_VALUE;
|
||||
|
||||
Set<String> authorisations = permissionService.getAuthorisations();
|
||||
this.isAdminReading = authorisations.contains(AuthenticationUtil.getAdminRoleName());
|
||||
|
||||
authority = aclCrudDAO.getAuthority(AuthenticationUtil.getRunAsUser());
|
||||
}
|
||||
|
||||
public boolean isIncluded(Node node)
|
||||
{
|
||||
if (isFirstRecord())
|
||||
{
|
||||
this.startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
checksPerformed++;
|
||||
return isReallyIncluded(node);
|
||||
}
|
||||
|
||||
public boolean isFirstRecord()
|
||||
{
|
||||
return checksPerformed == 0;
|
||||
}
|
||||
|
||||
boolean isReallyIncluded(Node node)
|
||||
{
|
||||
return isAdminReading ||
|
||||
canRead(node.getAclId()) ||
|
||||
isOwnerReading(node, authority);
|
||||
}
|
||||
|
||||
public void setMaxPermissionChecks(int maxPermissionChecks)
|
||||
{
|
||||
this.maxPermissionChecks = maxPermissionChecks;
|
||||
}
|
||||
|
||||
public boolean shouldQuitChecks()
|
||||
{
|
||||
boolean result = false;
|
||||
|
||||
if (checksPerformed >= maxPermissionChecks)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
if ((System.currentTimeMillis() - startTime) >= maxPermissionCheckTimeMillis)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setMaxPermissionCheckTimeMillis(long maxPermissionCheckTimeMillis)
|
||||
{
|
||||
this.maxPermissionCheckTimeMillis = maxPermissionCheckTimeMillis;
|
||||
}
|
||||
|
||||
boolean canRead(Long aclId)
|
||||
{
|
||||
aclReadStopWatch().start();
|
||||
try
|
||||
{
|
||||
Boolean res = aclReadCache.get(aclId);
|
||||
if (res == null)
|
||||
{
|
||||
res = canCurrentUserRead(aclId);
|
||||
aclReadCache.put(aclId, res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
finally
|
||||
{
|
||||
aclReadStopWatch().stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean canCurrentUserRead(Long aclId)
|
||||
{
|
||||
// cache resolved ACLs
|
||||
|
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 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.repo.search.impl.querymodel.impl.db;
|
||||
|
||||
import static org.alfresco.repo.search.impl.querymodel.impl.db.DBStats.aclOwnerStopWatch;
|
||||
import static org.alfresco.repo.search.impl.querymodel.impl.db.DBStats.aclReadStopWatch;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.cache.lookup.EntityLookupCache;
|
||||
import org.alfresco.repo.domain.node.Node;
|
||||
import org.alfresco.repo.domain.permissions.Authority;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.EqualsHelper;
|
||||
|
||||
public class NodePermissionAssessor
|
||||
{
|
||||
private final boolean isSystemReading;
|
||||
private final boolean isAdminReading;
|
||||
private final boolean isNullReading;
|
||||
private final Authority authority;
|
||||
private final Map<Long, Boolean> aclReadCache = new HashMap<>();
|
||||
private int checksPerformed;
|
||||
private long startTime;
|
||||
private int maxPermissionChecks;
|
||||
private long maxPermissionCheckTimeMillis;
|
||||
|
||||
private EntityLookupCache<Long, Node, NodeRef> nodesCache;
|
||||
private NodeService nodeService;
|
||||
private PermissionService permissionService;
|
||||
|
||||
public NodePermissionAssessor(NodeService nodeService, PermissionService permissionService,
|
||||
Authority authority, EntityLookupCache<Long, Node, NodeRef> nodeCache)
|
||||
{
|
||||
this.permissionService = permissionService;
|
||||
this.nodesCache = nodeCache;
|
||||
this.nodeService = nodeService;
|
||||
|
||||
this.checksPerformed = 0;
|
||||
this.maxPermissionChecks = Integer.MAX_VALUE;
|
||||
this.maxPermissionCheckTimeMillis = Long.MAX_VALUE;
|
||||
|
||||
Set<String> authorisations = permissionService.getAuthorisations();
|
||||
this.isSystemReading = AuthenticationUtil.isRunAsUserTheSystemUser();
|
||||
this.isAdminReading = authorisations.contains(AuthenticationUtil.getAdminRoleName());
|
||||
this.isNullReading = AuthenticationUtil.getRunAsUser() == null;
|
||||
|
||||
this.authority = authority;
|
||||
}
|
||||
|
||||
public boolean isIncluded(Node node)
|
||||
{
|
||||
if (isFirstRecord())
|
||||
{
|
||||
this.startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
checksPerformed++;
|
||||
return isReallyIncluded(node);
|
||||
}
|
||||
|
||||
public boolean isFirstRecord()
|
||||
{
|
||||
return checksPerformed == 0;
|
||||
}
|
||||
|
||||
protected boolean isOwnerReading(Node node, Authority authority)
|
||||
{
|
||||
aclOwnerStopWatch().start();
|
||||
try
|
||||
{
|
||||
if (authority == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
String owner = getOwner(node);
|
||||
return EqualsHelper.nullSafeEquals(authority.getAuthority(), owner);
|
||||
}
|
||||
finally
|
||||
{
|
||||
aclOwnerStopWatch().stop();
|
||||
}
|
||||
}
|
||||
|
||||
private String getOwner(Node node)
|
||||
{
|
||||
nodesCache.setValue(node.getId(), node);
|
||||
Set<QName> nodeAspects = nodeService.getAspects(node.getNodeRef());
|
||||
|
||||
String userName = null;
|
||||
if (nodeAspects.contains(ContentModel.ASPECT_AUDITABLE))
|
||||
{
|
||||
userName = node.getAuditableProperties().getAuditCreator();
|
||||
}
|
||||
else if (nodeAspects.contains(ContentModel.ASPECT_OWNABLE))
|
||||
{
|
||||
Serializable owner = nodeService.getProperty(node.getNodeRef(), ContentModel.PROP_OWNER);
|
||||
userName = DefaultTypeConverter.INSTANCE.convert(String.class, owner);
|
||||
}
|
||||
|
||||
return userName;
|
||||
}
|
||||
|
||||
boolean isReallyIncluded(Node node)
|
||||
{
|
||||
if (isNullReading)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return isSystemReading ||
|
||||
isAdminReading ||
|
||||
canRead(node.getAclId()) ||
|
||||
isOwnerReading(node, authority);
|
||||
}
|
||||
|
||||
public void setMaxPermissionChecks(int maxPermissionChecks)
|
||||
{
|
||||
this.maxPermissionChecks = maxPermissionChecks;
|
||||
}
|
||||
|
||||
public boolean shouldQuitChecks()
|
||||
{
|
||||
boolean result = false;
|
||||
|
||||
if (checksPerformed >= maxPermissionChecks)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
if ((System.currentTimeMillis() - startTime) >= maxPermissionCheckTimeMillis)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setMaxPermissionCheckTimeMillis(long maxPermissionCheckTimeMillis)
|
||||
{
|
||||
this.maxPermissionCheckTimeMillis = maxPermissionCheckTimeMillis;
|
||||
}
|
||||
|
||||
protected boolean canRead(Long aclId)
|
||||
{
|
||||
aclReadStopWatch().start();
|
||||
try
|
||||
{
|
||||
Boolean res = aclReadCache.get(aclId);
|
||||
if (res == null)
|
||||
{
|
||||
res = canCurrentUserRead(aclId);
|
||||
aclReadCache.put(aclId, res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
finally
|
||||
{
|
||||
aclReadStopWatch().stop();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean canCurrentUserRead(Long aclId)
|
||||
{
|
||||
// cache resolved ACLs
|
||||
Set<String> authorities = permissionService.getAuthorisations();
|
||||
|
||||
Set<String> aclReadersDenied = permissionService.getReadersDenied(aclId);
|
||||
for (String auth : aclReadersDenied)
|
||||
{
|
||||
if (authorities.contains(auth))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> aclReaders = permissionService.getReaders(aclId);
|
||||
for (String auth : aclReaders)
|
||||
{
|
||||
if (authorities.contains(auth))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -48,7 +48,6 @@ import org.alfresco.repo.domain.node.Node;
|
||||
import org.alfresco.repo.domain.node.NodeVersionKey;
|
||||
import org.alfresco.repo.domain.node.StoreEntity;
|
||||
import org.alfresco.repo.search.impl.querymodel.QueryOptions;
|
||||
import org.alfresco.repo.search.impl.querymodel.impl.db.DBQueryEngine.NodePermissionAssessor;
|
||||
import org.alfresco.repo.security.permissions.impl.acegi.FilteringResultSet;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchParameters;
|
||||
|
@@ -35,14 +35,17 @@ import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.alfresco.repo.cache.lookup.EntityLookupCache;
|
||||
import org.alfresco.repo.domain.node.Node;
|
||||
import org.alfresco.repo.domain.permissions.AclCrudDAO;
|
||||
import org.alfresco.repo.search.impl.querymodel.impl.db.DBQueryEngine.NodePermissionAssessor;
|
||||
import org.alfresco.repo.domain.permissions.Authority;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class NodePermissionAssessorTest
|
||||
public class NodePermissionAssessorLimitsTest
|
||||
{
|
||||
private NodePermissionAssessor assessor;
|
||||
private Node node;
|
||||
@@ -118,7 +121,10 @@ public class NodePermissionAssessorTest
|
||||
engine.setPermissionService(permissionService);
|
||||
engine.setAclCrudDAO(aclCrudDAO);
|
||||
|
||||
NodePermissionAssessor assessor = spy(engine.new NodePermissionAssessor());
|
||||
NodeService nodeService = mock(NodeService.class);
|
||||
Authority authority = mock(Authority.class);
|
||||
EntityLookupCache<Long, Node, NodeRef> nodeCache = mock(EntityLookupCache.class);
|
||||
NodePermissionAssessor assessor = spy(new NodePermissionAssessor(nodeService, permissionService, authority, nodeCache));
|
||||
doReturn(true).when(assessor).isReallyIncluded(any(Node.class));
|
||||
return assessor;
|
||||
}
|
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2021 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.repo.search.impl.querymodel.impl.db;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.cache.lookup.EntityLookupCache;
|
||||
import org.alfresco.repo.domain.node.Node;
|
||||
import org.alfresco.repo.domain.permissions.Authority;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class NodePermissionAssessorPermissionsTest
|
||||
{
|
||||
private PermissionService permissionService;
|
||||
|
||||
@Before
|
||||
public void setup()
|
||||
{
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
permissionService = mock(PermissionService.class);
|
||||
DBStats.resetStopwatches();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGrantPermissionWhenSystemIsReading()
|
||||
{
|
||||
// setup
|
||||
AuthenticationUtil.setRunAsUserSystem();
|
||||
|
||||
Node theNode = mock(Node.class);
|
||||
NodePermissionAssessor assessor = createAssessor();
|
||||
when(assessor.isOwnerReading(any(Node.class), any(Authority.class))).thenReturn(false);
|
||||
when(permissionService.getReaders(anyLong())).thenReturn(Set.of());
|
||||
|
||||
// call the assessor
|
||||
boolean included = assessor.isIncluded(theNode);
|
||||
|
||||
// the node is included
|
||||
assertTrue(included);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDenyPermissionWhenNullUserIsReading()
|
||||
{
|
||||
// setup - AuthenticationUtil.getRunAsUser() will return null
|
||||
Node theNode = mock(Node.class);
|
||||
NodePermissionAssessor assessor = createAssessor();
|
||||
when(assessor.isOwnerReading(any(Node.class), any(Authority.class))).thenReturn(false);
|
||||
when(permissionService.getReaders(anyLong())).thenReturn(Set.of());
|
||||
|
||||
// call the assessor
|
||||
boolean included = assessor.isIncluded(theNode);
|
||||
|
||||
// the node is included
|
||||
assertFalse(included);
|
||||
}
|
||||
|
||||
private NodePermissionAssessor createAssessor()
|
||||
{
|
||||
NodeService nodeService = mock(NodeService.class);
|
||||
Authority authority = mock(Authority.class);
|
||||
EntityLookupCache<Long, Node, NodeRef> nodeCache = mock(EntityLookupCache.class);
|
||||
return spy(new NodePermissionAssessor(nodeService, permissionService, authority, nodeCache));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user