diff --git a/source/java/org/alfresco/repo/lock/LockServiceImpl.java b/source/java/org/alfresco/repo/lock/LockServiceImpl.java index 66094d8585..d5144ad238 100644 --- a/source/java/org/alfresco/repo/lock/LockServiceImpl.java +++ b/source/java/org/alfresco/repo/lock/LockServiceImpl.java @@ -66,6 +66,8 @@ import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; import org.alfresco.util.Pair; import org.alfresco.util.PropertyCheck; @@ -94,6 +96,7 @@ public class LockServiceImpl implements LockService, private TenantService tenantService; private AuthenticationService authenticationService; private SearchService searchService; + private AuthorityService authorityService; private BehaviourFilter behaviourFilter; private LockStore lockStore; private PolicyComponent policyComponent; @@ -139,6 +142,10 @@ public class LockServiceImpl implements LockService, this.searchService = searchService; } + public void setAuthorityService(AuthorityService authorityService) { + this.authorityService = authorityService; + } + /** * Initialise methods called by Spring framework */ @@ -473,6 +480,8 @@ public class LockServiceImpl implements LockService, if (lockState.isLockInfo()) { + // check if the node is the user able to unlock the node + checkForLockIfNotAdmin(nodeRef); // MNT-231: forbidden to unlock a checked out node if (!allowCheckedOut && nodeService.hasAspect(nodeRef, ContentModel.ASPECT_CHECKED_OUT)) { @@ -503,8 +512,8 @@ public class LockServiceImpl implements LockService, } else if (lifetime == Lifetime.EPHEMERAL) { - // Remove the ephemeral lock. - lockStore.set(nodeRef, LockState.createUnlocked(nodeRef)); + // force unlock the ephemeral lock. + lockStore.forceUnlock(nodeRef); nodeIndexer.indexUpdateNode(nodeRef); } else @@ -656,6 +665,16 @@ public class LockServiceImpl implements LockService, } } } + + private void checkForLockIfNotAdmin(NodeRef nodeRef) + { + Set userAuthorities = authorityService.getAuthoritiesForUser(AuthenticationUtil.getRunAsUser()); + // ignore checkForLock for admins + if (!userAuthorities.contains(PermissionService.ADMINISTRATOR_AUTHORITY)) + { + checkForLock(nodeRef); + } + } /** * Ensures that the parent is not locked. diff --git a/source/java/org/alfresco/repo/lock/mem/AbstractLockStore.java b/source/java/org/alfresco/repo/lock/mem/AbstractLockStore.java index e842cdf19d..894b0f3d39 100644 --- a/source/java/org/alfresco/repo/lock/mem/AbstractLockStore.java +++ b/source/java/org/alfresco/repo/lock/mem/AbstractLockStore.java @@ -67,9 +67,20 @@ public abstract class AbstractLockStore txMap = getTxMap(); LockState previousLockState = null; @@ -102,7 +113,7 @@ public abstract class AbstractLockStore getNodes(); + /** + * WARNING: only use in lockService - unlocks node ignoring lockOwner + * + * @param nodeRef + */ + void forceUnlock(NodeRef nodeRef); + /** * WARNING: only use in test code - unsafe method for production use. * diff --git a/source/test-java/org/alfresco/repo/lock/LockServiceImplTest.java b/source/test-java/org/alfresco/repo/lock/LockServiceImplTest.java index 59eccc7fec..092f459409 100644 --- a/source/test-java/org/alfresco/repo/lock/LockServiceImplTest.java +++ b/source/test-java/org/alfresco/repo/lock/LockServiceImplTest.java @@ -33,6 +33,7 @@ import org.alfresco.repo.lock.mem.LockStore; import org.alfresco.repo.search.IndexerAndSearcher; import org.alfresco.repo.search.SearcherComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.lock.LockStatus; @@ -903,5 +904,41 @@ public class LockServiceImplTest extends BaseSpringTest logger.debug("exception while trying to unlock a checked out node", e); } } - + + public void testUnlockEphemeralNodeWithAdminUser() + { + for (Lifetime lt : new Lifetime[]{Lifetime.EPHEMERAL, Lifetime.PERSISTENT}) + { + TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService); + + /* create node */ + final NodeRef testNode = + this.nodeService.createNode(parentNode, ContentModel.ASSOC_CONTAINS, QName.createQName("{}testNode"), ContentModel.TYPE_CONTAINER).getChildRef(); + + // lock it as GOOD user + this.lockService.lock(testNode, LockType.WRITE_LOCK, 2 * 86400, lt, null); + + TestWithUserUtils.authenticateUser(BAD_USER_NAME, PWD, rootNodeRef, this.authenticationService); + + try + { + // try to unlock as bad user + this.lockService.unlock(testNode); + fail("BAD user shouldn't be able to unlock " + lt + " lock"); + } + catch(NodeLockedException e) + { + // it's expected + } + + TestWithUserUtils.authenticateUser(AuthenticationUtil.getAdminUserName(), "admin", rootNodeRef, this.authenticationService); + + // try to unlock as ADMIN user + this.lockService.unlock(testNode); + + TestWithUserUtils.authenticateUser(GOOD_USER_NAME, PWD, rootNodeRef, this.authenticationService); + + this.nodeService.deleteNode(testNode); + } + } }