diff --git a/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-2.2-ACL.sql b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-2.2-ACL.sql index 6f0ad8655d..f6b6a6a586 100644 --- a/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-2.2-ACL.sql +++ b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-2.2-ACL.sql @@ -75,9 +75,11 @@ ALTER TABLE alf_access_control_entry DROP INDEX FKFFF41F99B25A50BF, DROP FOREIGN ALTER TABLE alf_authority DROP PRIMARY KEY, ADD COLUMN id BIGINT NOT NULL AUTO_INCREMENT, + ADD COLUMN crc BIGINT, CHANGE recipient authority VARCHAR(100), ADD primary key (id), - ADD UNIQUE (authority); + ADD UNIQUE (authority, crc); +CREATE INDEX idx_authority on alf_authority (authority); -- migrate data - fix up FK refs to authority UPDATE alf_access_control_entry ace diff --git a/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java index 65bd51b708..03e8f08b10 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/WCMPermissionPatch.java @@ -46,9 +46,7 @@ import org.alfresco.service.namespace.RegexQNamePattern; /** * Remove ACLs on all but staging area stores On staging area stores, set ACls according to the users and roles as set - * on the web site - * - * Note: runs as the system user + * on the web site Note: runs as the system user * * @author andyh */ @@ -61,7 +59,7 @@ public class WCMPermissionPatch extends AbstractPatch AVMService avmService; PermissionService permissionService; - + public void setAvmService(AVMService avmService) { this.avmService = avmService; @@ -88,6 +86,7 @@ public class WCMPermissionPatch extends AbstractPatch /* Set permissions in staging */ case STAGING: setStagingAreaPermissions(store); + setStagingAreaMasks(store); // TODO: mark read only break; /* Clear permissions */ @@ -97,9 +96,11 @@ public class WCMPermissionPatch extends AbstractPatch case AUTHOR_WORKFLOW_PREVIEW: // TODO: add app access control clearPermissions(store); + setSandBoxMasks(store); break; case STAGING_PREVIEW: clearPermissions(store); + setStagingAreaMasks(store); // TODO: mark read only break; case WORKFLOW: @@ -109,7 +110,6 @@ public class WCMPermissionPatch extends AbstractPatch /* non WCM stores - nothing to do */ case UNKNOWN: default: - break; } } @@ -122,7 +122,7 @@ public class WCMPermissionPatch extends AbstractPatch private void clearPermissions(AVMStoreDescriptor store) { AVMNodeDescriptor www = avmService.lookup(-1, store.getName() + ":/www"); - if(www.isLayeredDirectory() && www.isPrimary()) + if (www.isLayeredDirectory() && www.isPrimary()) { // throw away any acl AVMRepository.GetInstance().setACL(store.getName() + ":/www", null); @@ -130,7 +130,6 @@ public class WCMPermissionPatch extends AbstractPatch avmService.retargetLayeredDirectory(store.getName() + ":/www", www.getIndirection()); } } - private void setStagingAreaPermissions(AVMStoreDescriptor store) { @@ -143,8 +142,8 @@ public class WCMPermissionPatch extends AbstractPatch if (pValue != null) { - NodeRef webProjectNodeRef = (NodeRef)pValue.getValue(DataTypeDefinition.NODE_REF); - + NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF); + // Apply sepcific user permissions as set on the web project List userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL); for (ChildAssociationRef ref : userInfoRefs) @@ -158,4 +157,75 @@ public class WCMPermissionPatch extends AbstractPatch } } + private void setStagingAreaMasks(AVMStoreDescriptor store) + { + NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, store.getName() + ":/www"); + permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ, true); + + } + + private void setSandBoxMasks(AVMStoreDescriptor sandBoxStore) + { + // get the settings from the staging store ... + + String owner = extractOwner(sandBoxStore.getName()); + String stagingAreaName = extractStagingAreaName(sandBoxStore.getName()); + + QName propQName = QName.createQName(null, ".web_project.noderef"); + + NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, sandBoxStore.getName() + ":/www"); + + PropertyValue pValue = avmService.getStoreProperty(stagingAreaName, propQName); + + permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ, true); + + if (pValue != null) + { + NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF); + + // Apply sepcific user permissions as set on the web project + List userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL); + for (ChildAssociationRef ref : userInfoRefs) + { + NodeRef userInfoRef = ref.getChildRef(); + String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME); + String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE); + + if (username.equals(owner)) + { + permissionService.setPermission(dirRef.getStoreRef(), username, PermissionService.ALL_PERMISSIONS, true); + } + else if (userrole.equals("ContentManager")) + { + permissionService.setPermission(dirRef.getStoreRef(), username, userrole, true); + } + } + } + } + + private String extractOwner(String name) + { + int start = name.indexOf("--"); + if (start == -1) + { + throw new UnsupportedOperationException(name); + } + int end = name.indexOf("--", start + 1); + if (end == -1) + { + return name.substring(start+2); + } + return name.substring(start + 2, end); + } + + private String extractStagingAreaName(String name) + { + int index = name.indexOf("--"); + if (index == -1) + { + throw new UnsupportedOperationException(name); + } + return name.substring(0, index); + } + } diff --git a/source/java/org/alfresco/repo/avm/AVMRepository.java b/source/java/org/alfresco/repo/avm/AVMRepository.java index 552aca0c17..986d418dd1 100644 --- a/source/java/org/alfresco/repo/avm/AVMRepository.java +++ b/source/java/org/alfresco/repo/avm/AVMRepository.java @@ -3230,13 +3230,29 @@ public class AVMRepository if (storeAcl != null) { Long storeAclID = storeAcl.getId(); - context.getAdditionalContext().put("STORE_ACL_ID", storeAclID); + context.setStoreAcl(storeAclID); } } return fPermissionService.hasPermission(aclId, context, permission) == AccessStatus.ALLOWED; } + public boolean can(String storeName, int version, String path, String permission) + { + Lookup lookup = AVMRepository.GetInstance().lookup(version, path, true); + if (lookup != null) + { + AVMNode node = lookup.getCurrentNode(); + AVMStore store = getAVMStoreByName(storeName); + return can(store, node, permission); + } + else + { + // Does not exist => allowed + return true; + } + } + /** * Set the acl on a store. * @param storeName diff --git a/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java b/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java index 1fca77574a..4e77d515a1 100644 --- a/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java @@ -75,7 +75,7 @@ import junit.framework.TestCase; /** * Specifically test AVM permissions with the updated ACL schema - * + * * @author andyh */ public class AVMServicePermissionsTest extends TestCase @@ -139,7 +139,7 @@ public class AVMServicePermissionsTest extends TestCase aclDaoComponent = (AclDaoComponent) applicationContext.getBean("aclDaoComponent"); avmService = (AVMService) applicationContext.getBean("avmService"); - avmSyncService = (AVMSyncService)applicationContext.getBean("AVMSyncService"); + avmSyncService = (AVMSyncService) applicationContext.getBean("AVMSyncService"); nodeService = (NodeService) applicationContext.getBean("nodeService"); dictionaryService = (DictionaryService) applicationContext.getBean(ServiceRegistry.DICTIONARY_SERVICE.getLocalName()); @@ -328,7 +328,9 @@ public class AVMServicePermissionsTest extends TestCase runAs(user); AVMNodeDescriptor desc = avmService.lookup(-1, path); AVMNode node = avmNodeDAO.getByID(desc.getId()); - boolean can = AVMRepository.GetInstance().can(null, node, permission); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, path); + AVMStore store = AVMDAOs.Instance().fAVMStoreDAO.getByName(nodeRef.getStoreRef().getIdentifier()); + boolean can = AVMRepository.GetInstance().can(store, node, permission); return allowed ? can : !can; } finally @@ -345,14 +347,17 @@ public class AVMServicePermissionsTest extends TestCase runAs(user); AVMNodeDescriptor desc = avmService.lookup(-1, path); AVMNode node = avmNodeDAO.getByID(desc.getId()); - boolean can = AVMRepository.GetInstance().can(null, node, permission); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, path); + AVMStore store = AVMDAOs.Instance().fAVMStoreDAO.getByName(nodeRef.getStoreRef().getIdentifier()); + boolean can = AVMRepository.GetInstance().can(store, node, permission); long start = System.nanoTime(); - for(int i = 0; i < count; i++) + for (int i = 0; i < count; i++) { can = AVMRepository.GetInstance().can(null, node, permission); } long end = System.nanoTime(); - System.out.println("Can in "+((end-start)/1.0e9f)); + System.out.println("Can in " + ((end - start) / 10e9f / count)); + System.out.println("Can per second " + (1 / ((end - start) / 10e9f / count))); return allowed ? can : !can; } finally @@ -370,12 +375,13 @@ public class AVMServicePermissionsTest extends TestCase NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, path); boolean can = permissionService.hasPermission(nodeRef, permission) == AccessStatus.ALLOWED; long start = System.nanoTime(); - for(int i = 0; i < count; i++) + for (int i = 0; i < count; i++) { can = permissionService.hasPermission(nodeRef, permission) == AccessStatus.ALLOWED; } long end = System.nanoTime(); - System.out.println("Has Permission in "+((end-start)/1.0e9f)); + System.out.println("Has Permission in " + ((end - start) / 10e9f / count)); + System.out.println("Has Permission per second " + (1 / ((end - start) / 10e9f / count))); return allowed ? can : !can; } finally @@ -384,7 +390,114 @@ public class AVMServicePermissionsTest extends TestCase } } + public boolean checkHasPermission(String user, NodeRef nodeRef, String permission, boolean allowed) + { + String curentUser = AuthenticationUtil.getCurrentUserName(); + try + { + runAs(user); + boolean can = permissionService.hasPermission(nodeRef, permission) == AccessStatus.ALLOWED; + return allowed ? can : !can; + } + finally + { + runAs(curentUser); + } + } + + public void testStoreAcls() throws Exception + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + buildBaseStructure(storeName); + AVMNodeDescriptor nodeDesc = avmService.lookup(-1, storeName + ":/base"); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, nodeDesc.getPath()); + permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + + permissionService.setPermission(nodeRef.getStoreRef(), "andy", PermissionService.ALL_PERMISSIONS, true); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + + permissionService.deletePermission(nodeRef.getStoreRef(), "andy", PermissionService.ALL_PERMISSIONS); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + + permissionService.deletePermissions(nodeRef.getStoreRef()); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + + + permissionService.setPermission(nodeRef.getStoreRef(), "andy", PermissionService.ALL_PERMISSIONS, true); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + permissionService.setPermission(nodeRef.getStoreRef(), "andy", PermissionService.READ, true); + permissionService.setPermission(nodeRef.getStoreRef(), "lemur", PermissionService.ALL_PERMISSIONS, true); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertEquals(permissionService.getAllSetPermissions(nodeRef.getStoreRef()).size(), 3); + + permissionService.clearPermission(nodeRef.getStoreRef(), "andy"); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + assertEquals(permissionService.getAllSetPermissions(nodeRef.getStoreRef()).size(), 1); + + permissionService.clearPermission(nodeRef.getStoreRef(), "lemur"); + + assertTrue(checkPermission("andy", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("andy", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkHasPermission("lemur", nodeRef, PermissionService.ALL_PERMISSIONS, false)); + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.ALL_PERMISSIONS, true)); + assertTrue(checkHasPermission("admin", nodeRef, PermissionService.ALL_PERMISSIONS, true)); + + } + finally + { + avmService.purgeStore(storeName); + avmService.purgeStore(storeName + "-layer-base"); + avmService.purgeStore(storeName + "-layer-a"); + avmService.purgeStore(storeName + "-layer-b"); + avmService.purgeStore(storeName + "-layer-c"); + avmService.purgeStore(storeName + "-layer-d"); + avmService.purgeStore(storeName + "-layer-layer-base"); + avmService.purgeStore(storeName + "-layer-layer-layer-base"); + } + + } public void testSimpleUpdate() throws Exception { @@ -415,7 +528,6 @@ public class AVMServicePermissionsTest extends TestCase assertNotNull(fileAcl); assertTrue(acl.getId() == fileAcl.getId()); - avmService.createSnapshot(storeName, "store", "store"); avmService.createSnapshot(storeName + "-layer-base", "store", "store"); @@ -423,7 +535,6 @@ public class AVMServicePermissionsTest extends TestCase avmSyncService.update(diffs, null, false, false, false, false, "A", "A"); - desc = avmService.lookup(-1, storeName + ":/base/update-dir"); node = avmNodeDAO.getByID(desc.getId()); dirAcl = node.getAcl(); @@ -472,7 +583,6 @@ public class AVMServicePermissionsTest extends TestCase Long baseAcl = avmNodeDAO.getByID(nodeDesc.getId()).getAcl().getId(); Long inheritedBaseAcl = aclDaoComponent.getInheritedAccessControlList(baseAcl); - avmService.createDirectory(storeName + "-layer-base:/layer-to-base", "update-dir"); avmService.createFile(storeName + "-layer-base:/layer-to-base/update-dir", "update-file").close(); @@ -495,7 +605,6 @@ public class AVMServicePermissionsTest extends TestCase assertNotNull(fileAcl); assertTrue(acl.getId() == fileAcl.getId()); - avmService.createSnapshot(storeName, "store", "store"); avmService.createSnapshot(storeName + "-layer-base", "store", "store"); @@ -503,7 +612,6 @@ public class AVMServicePermissionsTest extends TestCase avmSyncService.update(diffs, null, false, false, false, false, "A", "A"); - desc = avmService.lookup(-1, storeName + ":/base/update-dir"); node = avmNodeDAO.getByID(desc.getId()); dirAcl = node.getAcl(); @@ -1860,7 +1968,7 @@ public class AVMServicePermissionsTest extends TestCase finally { avmService.purgeStore(storeName); - avmService.purgeStore(storeName+"-a-"); + avmService.purgeStore(storeName + "-a-"); } } @@ -2228,7 +2336,7 @@ public class AVMServicePermissionsTest extends TestCase finally { avmService.purgeStore(storeName); - avmService.purgeStore(storeName+"-a-"); + avmService.purgeStore(storeName + "-a-"); } } @@ -2547,7 +2655,7 @@ public class AVMServicePermissionsTest extends TestCase finally { avmService.purgeStore(storeName); - avmService.purgeStore(storeName+"-a-"); + avmService.purgeStore(storeName + "-a-"); } } @@ -2625,7 +2733,7 @@ public class AVMServicePermissionsTest extends TestCase finally { avmService.purgeStore(storeName); - avmService.purgeStore(storeName+"-a-"); + avmService.purgeStore(storeName + "-a-"); } } } diff --git a/source/java/org/alfresco/repo/domain/AccessControlListDAO.java b/source/java/org/alfresco/repo/domain/AccessControlListDAO.java index c703f70b40..6c487729ab 100644 --- a/source/java/org/alfresco/repo/domain/AccessControlListDAO.java +++ b/source/java/org/alfresco/repo/domain/AccessControlListDAO.java @@ -30,6 +30,7 @@ import java.util.Set; import org.alfresco.repo.security.permissions.ACLType; import org.alfresco.repo.security.permissions.impl.AclChange; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; /** * This abstracts the reading and writing of ACLs on nodes from particular node implementations. @@ -84,4 +85,8 @@ public interface AccessControlListDAO public void forceCopy(NodeRef nodeRef); public Map patchAcls(); + + public DbAccessControlList getAccessControlList(StoreRef storeRef); + + public void setAccessControlList(StoreRef storeRef, DbAccessControlList acl); } diff --git a/source/java/org/alfresco/repo/domain/DbAuthority.java b/source/java/org/alfresco/repo/domain/DbAuthority.java index 59b889098e..78484e6501 100644 --- a/source/java/org/alfresco/repo/domain/DbAuthority.java +++ b/source/java/org/alfresco/repo/domain/DbAuthority.java @@ -52,5 +52,18 @@ public interface DbAuthority extends Serializable * @param the authority */ public void setAuthority(String authority); + + /** + * Use a crc to enforce case sensitive unique key + * @param crc + */ + public void setCrc(Long crc); + + /** + * Get the CRC + * + * @return + */ + public Long getCrc(); } diff --git a/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java b/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java index f3ad2d8d6a..d89dad4d1f 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java +++ b/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java @@ -48,7 +48,9 @@ import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.InvalidStoreRefException; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.util.Pair; /** @@ -814,7 +816,26 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } } + private DbAccessControlList getStoreAclAsSystem(final String storeName) + { + return AuthenticationUtil.runAs(new RunAsWork(){ + + public DbAccessControlList doWork() throws Exception + { + return fAVMRepository.getStoreAcl(storeName); + }}, AuthenticationUtil.getSystemUserName()); + } + private void setStoreAclAsSystem(final String storeName, final DbAccessControlList acl) + { + AuthenticationUtil.runAs(new RunAsWork(){ + + public Object doWork() throws Exception + { + fAVMRepository.setStoreAcl(storeName, acl); + return null; + }}, AuthenticationUtil.getSystemUserName()); + } private DbAccessControlList getAclAsSystem(final int version, final String path) { @@ -836,4 +857,30 @@ public class AVMAccessControlListDAO implements AccessControlListDAO return null; }}, AuthenticationUtil.getSystemUserName()); } + + public DbAccessControlList getAccessControlList(StoreRef storeRef) + { + try + { + return getStoreAclAsSystem(storeRef.getIdentifier()); + } + catch (AVMException e) + { + throw new InvalidStoreRefException(storeRef); + } + } + + public void setAccessControlList(StoreRef storeRef, DbAccessControlList acl) + { + try + { + setStoreAclAsSystem(storeRef.getIdentifier(), acl); + } + catch (AVMException e) + { + throw new InvalidStoreRefException(storeRef); + } + } + + } diff --git a/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java index 206a245a5f..4f8f5e2445 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java @@ -34,12 +34,14 @@ import java.util.Set; import org.alfresco.repo.domain.AccessControlListDAO; import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.security.permissions.ACEType; +import org.alfresco.repo.security.permissions.ACLType; import org.alfresco.repo.security.permissions.AccessControlEntry; import org.alfresco.repo.security.permissions.AccessControlList; import org.alfresco.repo.security.permissions.NodePermissionEntry; import org.alfresco.repo.security.permissions.PermissionEntry; import org.alfresco.repo.security.permissions.PermissionReference; import org.alfresco.repo.security.permissions.SimpleAccessControlEntry; +import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; import org.alfresco.repo.security.permissions.impl.AclChange; import org.alfresco.repo.security.permissions.impl.AclDaoComponent; import org.alfresco.repo.security.permissions.impl.PermissionsDaoComponent; @@ -48,6 +50,7 @@ import org.alfresco.repo.security.permissions.impl.SimplePermissionEntry; import org.alfresco.repo.transaction.TransactionalDao; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.util.GUID; @@ -267,6 +270,30 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions return snpe; } } + + private SimpleNodePermissionEntry createSimpleNodePermissionEntry(StoreRef storeRef) + { + DbAccessControlList acl = getACLDAO(storeRef).getAccessControlList(storeRef); + if (acl == null) + { + // there isn't an access control list for the node - spoof a null one + SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(null, true, Collections. emptySet()); + return snpe; + } + else + { + AccessControlList info = aclDaoComponent.getAccessControlList(acl.getId()); + + HashSet spes = new HashSet(info.getEntries().size(), 1.0f); + for (AccessControlEntry entry : info.getEntries()) + { + SimplePermissionEntry spe = new SimplePermissionEntry(null, entry.getPermission(), entry.getAuthority(), entry.getAccessStatus()); + spes.add(spe); + } + SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(null, acl.getInherits(), spes); + return snpe; + } + } public boolean getInheritParentPermissions(NodeRef nodeRef) { @@ -456,6 +483,117 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions getACLDAO(nodeRef).updateChangedAcls(nodeRef, all); } + + + public void deletePermission(StoreRef storeRef, String authority, PermissionReference permission) + { + DbAccessControlList acl = getAccessControlList(storeRef); + if(acl == null) + { + return; + } + acl = getMutableAccessControlList(storeRef); + SimpleAccessControlEntry pattern = new SimpleAccessControlEntry(); + pattern.setAuthority(authority); + pattern.setPermission(permission); + aclDaoComponent.deleteAccessControlEntries(acl.getId(), pattern); + } + + private DbAccessControlList getMutableAccessControlList(StoreRef storeRef) + { + DbAccessControlList acl = getACLDAO(storeRef).getAccessControlList(storeRef); + if(acl == null) + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setVersioned(false); + properties.setInherits(false); + // Accept default versioning + Long id = aclDaoComponent.createAccessControlList(properties); + acl = aclDaoComponent.getDbAccessControlList(id); + getACLDAO(storeRef).setAccessControlList(storeRef, acl); + } + return acl; + } + + private AccessControlListDAO getACLDAO(StoreRef storeRef) + { + AccessControlListDAO ret = fProtocolToACLDAO.get(storeRef.getProtocol()); + if (ret == null) + { + return fDefaultACLDAO; + } + return ret; + } + + private DbAccessControlList getAccessControlList(StoreRef storeRef) + { + return getACLDAO(storeRef).getAccessControlList(storeRef); + } + + public void deletePermissions(StoreRef storeRef, String authority) + { + DbAccessControlList acl = getAccessControlList(storeRef); + if(acl == null) + { + return; + } + acl = getMutableAccessControlList(storeRef); + SimpleAccessControlEntry pattern = new SimpleAccessControlEntry(); + pattern.setAuthority(authority); + aclDaoComponent.deleteAccessControlEntries(acl.getId(), pattern); + } + + public void deletePermissions(StoreRef storeRef) + { + getACLDAO(storeRef).setAccessControlList(storeRef, null); + } + + public void setPermission(StoreRef storeRef, String authority, PermissionReference permission, boolean allow) + { + DbAccessControlList acl = getMutableAccessControlList(storeRef); + + SimpleAccessControlEntry entry = new SimpleAccessControlEntry(); + entry.setAuthority(authority); + entry.setPermission(permission); + entry.setAccessStatus(allow ? AccessStatus.ALLOWED : AccessStatus.DENIED); + entry.setAceType(ACEType.ALL); + aclDaoComponent.setAccessControlEntry(acl.getId(), entry); + } + + + + public NodePermissionEntry getPermissions(StoreRef storeRef) + { + // Create the object if it is not found. + // Null objects are not cached in hibernate + // If the object does not exist it will repeatedly query to check its + // non existence. + NodePermissionEntry npe = null; + DbAccessControlList acl = null; + try + { + acl = getAccessControlList(storeRef); + } + catch (InvalidNodeRefException e) + { + // Do nothing. + } + + if (acl == null) + { + // there isn't an access control list for the node - spoof a null one + SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(null, true, Collections. emptySet()); + npe = snpe; + } + else + { + npe = createSimpleNodePermissionEntry(storeRef); + } + + return npe; + } + protected abstract CreationReport createAccessControlList(NodeRef nodeRef, boolean inherit, DbAccessControlList existing); static class CreationReport diff --git a/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java index e7d2ffd1ac..4dcbedd766 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java @@ -30,6 +30,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.zip.CRC32; import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.domain.DbAccessControlEntry; @@ -94,7 +95,7 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo /** a transactionally-safe cache to be injected */ private SimpleCache aclCache; - + private enum WriteMode { TRUNCATE_INHERITED, ADD_INHERITED, CHANGE_INHERITED, REMOVE_INHERITED, INSERT_INHERITED, COPY_UPDATE_AND_INHERIT, COPY_ONLY; @@ -106,15 +107,11 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo DbAccessControlListImpl.setAclDaoComponent(this); } - - public void setAclCache(SimpleCache aclCache) { this.aclCache = aclCache; } - - public DbAccessControlList getDbAccessControlList(Long id) { if (id == null) @@ -722,14 +719,18 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo for (Object[] ids : results) { - // Delete acl entry - DbAccessControlListMember member = (DbAccessControlListMember) getHibernateTemplate().get(DbAccessControlListMemberImpl.class, (Long) ids[0]); - Long aclId = ((Long) ids[1]); - aclCache.remove(aclId); - DbAccessControlList list = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, aclId); - acls.add(new AclChangeImpl(aclId, aclId, list.getAclType(), list.getAclType())); - getHibernateTemplate().delete(member); - aces.add((Long) ids[2]); + String authorityFound = (String) ids[3]; + if (authorityFound.equals(authority)) + { + // Delete acl entry + DbAccessControlListMember member = (DbAccessControlListMember) getHibernateTemplate().get(DbAccessControlListMemberImpl.class, (Long) ids[0]); + Long aclId = ((Long) ids[1]); + aclCache.remove(aclId); + DbAccessControlList list = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, aclId); + acls.add(new AclChangeImpl(aclId, aclId, list.getAclType(), list.getAclType())); + getHibernateTemplate().delete(member); + aces.add((Long) ids[2]); + } } // remove ACEs @@ -749,13 +750,16 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo { Query query = session.getNamedQuery(QUERY_GET_AUTHORITY); query.setParameter("authority", authority); - return query.uniqueResult(); + return query.list(); } }; - DbAuthority dbAuthority = (DbAuthority) getHibernateTemplate().execute(callback); - if (dbAuthority != null) + List authorities = (List) getHibernateTemplate().execute(callback); + for (DbAuthority found : authorities) { - getHibernateTemplate().delete(dbAuthority); + if (found.getAuthority().equals(authority)) + { + getHibernateTemplate().delete(found); + } } // TODO: Remove affected ACLs from the cache @@ -948,18 +952,18 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo public AccessControlList getAccessControlList(Long id) { AccessControlList acl = aclCache.get(id); - if(acl == null) + if (acl == null) { acl = getAccessControlListImpl(id); aclCache.put(id, acl); } else { - //System.out.println("Used cache for "+id); + // System.out.println("Used cache for "+id); } return acl; } - + @SuppressWarnings("unchecked") public AccessControlList getAccessControlListImpl(final Long id) { @@ -1194,14 +1198,24 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo { Query query = session.getNamedQuery(QUERY_GET_AUTHORITY); query.setParameter("authority", ace.getAuthority()); - return query.uniqueResult(); + return query.list(); } }; - DbAuthority authority = (DbAuthority) getHibernateTemplate().execute(callback); + DbAuthority authority = null; + List authorities = (List) getHibernateTemplate().execute(callback); + for(DbAuthority found : authorities) + { + if(found.getAuthority().equals(ace.getAuthority())) + { + authority = found; + break; + } + } if (authority == null) { DbAuthorityImpl newAuthority = new DbAuthorityImpl(); newAuthority.setAuthority(ace.getAuthority()); + newAuthority.setCrc(getCrc(ace.getAuthority())); authority = newAuthority; getHibernateTemplate().save(newAuthority); } @@ -1280,6 +1294,14 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo return changes; } + + private long getCrc(String str) + { + CRC32 crc = new CRC32(); + crc.update(str.getBytes()); + return crc.getValue(); + } + public List enableInheritance(Long id, Long parent) { List changes = new ArrayList(); diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityImpl.java index 8e26c653cb..9331f4d073 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityImpl.java @@ -29,7 +29,6 @@ import java.io.Serializable; import org.alfresco.repo.domain.DbAuthority; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.hibernate.CallbackException; import org.hibernate.Session; /** @@ -37,45 +36,44 @@ import org.hibernate.Session; * * @author andyh */ -public class DbAuthorityImpl - implements DbAuthority, Serializable +public class DbAuthorityImpl implements DbAuthority, Serializable { private static final long serialVersionUID = -5582068692208928127L; - + private static Log logger = LogFactory.getLog(DbAuthorityImpl.class); private Long id; + private Long version; + private String authority; + private Long crc; + public DbAuthorityImpl() { } - + @Override public String toString() { StringBuilder sb = new StringBuilder(128); - sb.append("DbAuthorityImpl") - .append("[ id=").append(id) - .append(", version=").append(version) - .append(", authority=").append(authority) - .append("]"); + sb.append("DbAuthorityImpl").append("[ id=").append(id).append(", version=").append(version).append(", authority=").append(authority).append("]"); return sb.toString(); } - + @Override public boolean equals(Object o) { - if(this == o) + if (this == o) { return true; } - if(!(o instanceof DbAuthority)) + if (!(o instanceof DbAuthority)) { return false; } - DbAuthority other = (DbAuthority)o; + DbAuthority other = (DbAuthority) o; return this.getAuthority().equals(other.getAuthority()); } @@ -89,19 +87,29 @@ public class DbAuthorityImpl { return id; } - + @SuppressWarnings("unused") private void setId(Long id) { this.id = id; } - - + + @SuppressWarnings("unused") + public void setCrc(Long crc) + { + this.crc = crc; + } + public Long getVersion() { return version; } + public Long getCrc() + { + return crc; + } + /** * For Hibernate use */ @@ -118,19 +126,21 @@ public class DbAuthorityImpl public void setAuthority(String authority) { - this.authority = authority; + this.authority = authority; } - + /** * Helper method to find an authority based on its natural key * - * @param session the Hibernate session to use - * @param authority the authority name + * @param session + * the Hibernate session to use + * @param authority + * the authority name * @return Returns an existing instance or null if not found */ public static DbAuthority find(Session session, String authority) { - // TODO: Needs to use a query + // TODO: Needs to use a query throw new UnsupportedOperationException("TODO"); } } diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateQNameDAOImpl.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateQNameDAOImpl.java index 731031648b..44b32ceade 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/HibernateQNameDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateQNameDAOImpl.java @@ -164,6 +164,14 @@ public class HibernateQNameDAOImpl extends HibernateDaoSupport implements QNameD // We found something, so we can add it to the cache qnameEntityCache.put(qname, id); } + else + { + qnameEntityCache.put(qname, -1L); + } + } + else if(id == -1L) + { + return null; } else { diff --git a/source/java/org/alfresco/repo/domain/hibernate/NodeAccessControlListDAO.java b/source/java/org/alfresco/repo/domain/hibernate/NodeAccessControlListDAO.java index a79ead44fa..f25f94acf4 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/NodeAccessControlListDAO.java +++ b/source/java/org/alfresco/repo/domain/hibernate/NodeAccessControlListDAO.java @@ -36,6 +36,7 @@ import org.alfresco.repo.security.permissions.ACLType; import org.alfresco.repo.security.permissions.impl.AclChange; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; /** * The Node implementation for getting and setting ACLs. @@ -146,4 +147,15 @@ public class NodeAccessControlListDAO implements AccessControlListDAO throw new UnsupportedOperationException(); } + public DbAccessControlList getAccessControlList(StoreRef storeRef) + { + throw new UnsupportedOperationException(); + } + + public void setAccessControlList(StoreRef storeRef, DbAccessControlList acl) + { + throw new UnsupportedOperationException(); + } + + } diff --git a/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml index 023c3c75e5..3fbe11567f 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml @@ -193,13 +193,15 @@ lazy="false" optimistic-lock="version" > - + - + + + @@ -317,7 +319,7 @@ select - aclmem.id, acl.id, ace.id + aclmem.id, acl.id, ace.id, authority.authority from org.alfresco.repo.domain.hibernate.DbAccessControlListMemberImpl as aclmem join aclmem.accessControlList as acl diff --git a/source/java/org/alfresco/repo/security/permissions/impl/AbstractNodePermissionEntry.java b/source/java/org/alfresco/repo/security/permissions/impl/AbstractNodePermissionEntry.java index e01176b0a3..0f1025e7bc 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/AbstractNodePermissionEntry.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/AbstractNodePermissionEntry.java @@ -25,31 +25,27 @@ package org.alfresco.repo.security.permissions.impl; import org.alfresco.repo.security.permissions.NodePermissionEntry; - +import org.alfresco.util.EqualsHelper; /** * This class provides common support for hash code and equality. * * @author andyh */ -public abstract class AbstractNodePermissionEntry implements - NodePermissionEntry +public abstract class AbstractNodePermissionEntry implements NodePermissionEntry { public AbstractNodePermissionEntry() { super(); } - + @Override public String toString() { StringBuilder sb = new StringBuilder(200); - sb.append("NodePermissionEntry") - .append("[ node=").append(getNodeRef()) - .append(", entries=").append(getPermissionEntries()) - .append(", inherits=").append(inheritPermissions()) - .append("]"); + sb.append("NodePermissionEntry").append("[ node=").append(getNodeRef()).append(", entries=").append(getPermissionEntries()).append(", inherits=").append( + inheritPermissions()).append("]"); return sb.toString(); } @@ -66,14 +62,21 @@ public abstract class AbstractNodePermissionEntry implements } AbstractNodePermissionEntry other = (AbstractNodePermissionEntry) o; - return this.getNodeRef().equals(other.getNodeRef()) - && (this.inheritPermissions() == other.inheritPermissions()) - && (this.getPermissionEntries().equals(other.getPermissionEntries())); + return EqualsHelper.nullSafeEquals(this.getNodeRef(), other.getNodeRef()) && + EqualsHelper.nullSafeEquals(this.inheritPermissions(), other.inheritPermissions()) && + EqualsHelper.nullSafeEquals(this.getPermissionEntries(), other.getPermissionEntries()); } @Override public int hashCode() { - return getNodeRef().hashCode(); + if (getNodeRef() != null) + { + return getNodeRef().hashCode(); + } + else + { + return 0; + } } } diff --git a/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionEntry.java b/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionEntry.java index 0ae0b024dc..f3f069cd94 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionEntry.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionEntry.java @@ -54,14 +54,17 @@ public abstract class AbstractPermissionEntry implements PermissionEntry AbstractPermissionEntry other = (AbstractPermissionEntry) o; return EqualsHelper.nullSafeEquals(this.getNodeRef(), other.getNodeRef()) && EqualsHelper.nullSafeEquals(this.getPermissionReference(), other.getPermissionReference()) - && EqualsHelper.nullSafeEquals(this.getAuthority(), other.getAuthority()) - && EqualsHelper.nullSafeEquals(this.getAccessStatus(), other.getAccessStatus()); + && EqualsHelper.nullSafeEquals(this.getAuthority(), other.getAuthority()) && EqualsHelper.nullSafeEquals(this.getAccessStatus(), other.getAccessStatus()); } @Override public int hashCode() { - int hashCode = getNodeRef().hashCode(); + int hashCode = 0; + if (getNodeRef() != null) + { + getNodeRef().hashCode(); + } if (getPermissionReference() != null) { hashCode = hashCode * 37 + getPermissionReference().hashCode(); @@ -70,9 +73,9 @@ public abstract class AbstractPermissionEntry implements PermissionEntry { hashCode = hashCode * 37 + getAuthority().hashCode(); } - if(getAccessStatus() != null) + if (getAccessStatus() != null) { - hashCode = hashCode * 37 + getAccessStatus().hashCode(); + hashCode = hashCode * 37 + getAccessStatus().hashCode(); } return hashCode; } @@ -81,13 +84,9 @@ public abstract class AbstractPermissionEntry implements PermissionEntry public String toString() { StringBuilder sb = new StringBuilder(200); - sb.append("PermissionEntry") - .append("[ authority=").append(getAuthority()) - .append(", permission=").append(getPermissionReference()) - .append(", access=").append(getAccessStatus()) - .append("]"); + sb.append("PermissionEntry").append("[ authority=").append(getAuthority()).append(", permission=").append(getPermissionReference()).append(", access=").append( + getAccessStatus()).append("]"); return sb.toString(); } - } diff --git a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java index b0448020d2..20df811789 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java @@ -36,6 +36,8 @@ import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.providers.dao.User; import org.alfresco.model.ContentModel; +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.repo.avm.AVMRepository; import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; @@ -54,6 +56,7 @@ import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ChildAssociationRef; 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.AccessPermission; import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AuthorityService; @@ -283,6 +286,17 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing return accessPermissions; } + public Set getAllSetPermissions(StoreRef storeRef) + { + HashSet accessPermissions = new HashSet(); + NodePermissionEntry nodePremissionEntry = getSetPermissions(storeRef); + for (PermissionEntry pe : nodePremissionEntry.getPermissionEntries()) + { + accessPermissions.add(new AccessPermissionImpl(getPermission(pe.getPermissionReference()), pe.getAccessStatus(), pe.getAuthority())); + } + return accessPermissions; + } + private Set getAllPermissionsImpl(NodeRef nodeRef, boolean includeTrue, boolean includeFalse) { String userName = authenticationComponent.getCurrentUserName(); @@ -331,6 +345,11 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing return permissionsDaoComponent.getPermissions(tenantService.getName(nodeRef)); } + public NodePermissionEntry getSetPermissions(StoreRef storeRef) + { + return permissionsDaoComponent.getPermissions(storeRef); + } + public AccessStatus hasPermission(final NodeRef nodeRefIn, final PermissionReference permIn) { // If the node ref is null there is no sensible test to do - and there @@ -349,12 +368,20 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing return AccessStatus.DENIED; } + // AVM nodes - test for existence underneath + if (nodeRef.getStoreRef().getProtocol().equals(StoreRef.PROTOCOL_AVM)) + { + return doAvmCan(nodeRef, permIn); + } + // Allow permissions for nodes that do not exist if (!nodeService.exists(nodeRef)) { return AccessStatus.ALLOWED; } + + final PermissionReference perm; if (permIn.equals(OLD_ALL_PERMISSIONS_REFERENCE)) { @@ -436,6 +463,16 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing } + private AccessStatus doAvmCan(NodeRef nodeRef, PermissionReference permission) + { + org.alfresco.util.Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + String path = avmVersionPath.getSecond(); + boolean result = AVMRepository.GetInstance().can(nodeRef.getStoreRef().getIdentifier(), version, path, permission.getName()); + AccessStatus status = result ? AccessStatus.ALLOWED : AccessStatus.DENIED; + return status; + } + /* * (non-Javadoc) * @@ -493,11 +530,22 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing { permission = getAllPermissionReference(); } - AclTest aclTest = new AclTest(permission, typeQname, aspectQNames); - boolean result = aclTest.evaluate(authorisations, aclId); + boolean result; + if (context.getStoreAcl() == null) + { + AclTest aclTest = new AclTest(permission, typeQname, aspectQNames); + result = aclTest.evaluate(authorisations, aclId); + } + else + { + Set storeAuthorisations = getAuthorisations(auth, (PermissionContext)null); + AclTest aclTest = new AclTest(permission, typeQname, aspectQNames); + result = aclTest.evaluate(authorisations, aclId) && aclTest.evaluate(storeAuthorisations, context.getStoreAcl()); + } AccessStatus status = result ? AccessStatus.ALLOWED : AccessStatus.DENIED; return status; + } enum CacheType @@ -608,6 +656,43 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing return null; } + public void clearPermission(StoreRef storeRef, String authority) + { + permissionsDaoComponent.deletePermissions(storeRef, authority); + accessCache.clear(); + + } + + public void deletePermission(StoreRef storeRef, String authority, String perm) + { + deletePermission(storeRef, authority, getPermissionReference(perm)); + } + + public void deletePermission(StoreRef storeRef, String authority, PermissionReference perm) + { + permissionsDaoComponent.deletePermission(storeRef, authority, perm); + accessCache.clear(); + } + + public void deletePermissions(StoreRef storeRef) + { + permissionsDaoComponent.deletePermissions(storeRef); + accessCache.clear(); + + } + + public void setPermission(StoreRef storeRef, String authority, String perm, boolean allow) + { + setPermission(storeRef, authority, getPermissionReference(perm), allow); + } + + public void setPermission(StoreRef storeRef, String authority, PermissionReference permission, boolean allow) + { + permissionsDaoComponent.setPermission(storeRef, authority, permission, allow); + accessCache.clear(); + + } + public void deletePermissions(NodeRef nodeRef) { permissionsDaoComponent.deletePermissions(tenantService.getName(nodeRef)); diff --git a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java index 1a982a8b76..9755df58e5 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java @@ -949,7 +949,42 @@ public class PermissionServiceTest extends AbstractPermissionTest assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); } + + public void testPerformance() throws Exception + { + runAs("admin"); + // TransactionService transactionService = serviceRegistry.getTransactionService(); + // UserTransaction tx = transactionService.getUserTransaction(); + // tx.begin(); + + NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n3 = nodeService.createNode(n2, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}three"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n4 = nodeService.createNode(n3, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}four"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n5 = nodeService.createNode(n4, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}five"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n6 = nodeService.createNode(n5, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}six"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n7 = nodeService.createNode(n6, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}seven"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n8 = nodeService.createNode(n7, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}eight"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n9 = nodeService.createNode(n8, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}nine"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n10 = nodeService.createNode(n9, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}ten"), ContentModel.TYPE_FOLDER).getChildRef(); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), "andy", AccessStatus.ALLOWED)); + + runAs("andy"); + permissionService.hasPermission(n5, PermissionService.READ); + long start = System.nanoTime(); + for(int i = 0; i < 10000; i++) + { + permissionService.hasPermission(n5, PermissionService.READ); + } + long end = System.nanoTime(); + System.out.println("Can in "+((end-start)/10e9f/10000)); + System.out.println("Can per second "+(1/((end-start)/10e9f/10000))); + + } + + public void testPerf() throws Exception { runAs("admin"); @@ -1527,6 +1562,8 @@ public class PermissionServiceTest extends AbstractPermissionTest permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES), "ANDY", AccessStatus.ALLOWED)); permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ_CONTENT), "AnDy", AccessStatus.ALLOWED)); + permissionService.getAllSetPermissions(rootNodeRef); + runAs("andy"); assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); diff --git a/source/java/org/alfresco/repo/security/permissions/impl/PermissionsDaoComponent.java b/source/java/org/alfresco/repo/security/permissions/impl/PermissionsDaoComponent.java index 7f0c7cdf57..35043ead38 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionsDaoComponent.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionsDaoComponent.java @@ -31,6 +31,7 @@ import org.alfresco.repo.security.permissions.NodePermissionEntry; import org.alfresco.repo.security.permissions.PermissionEntry; import org.alfresco.repo.security.permissions.PermissionReference; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.security.AccessPermission; /** @@ -137,4 +138,45 @@ public interface PermissionsDaoComponent * @return - the set of matching nodes */ public Set findNodeByPermission(String authority, PermissionReference permission, boolean allow); + + /** + * Delete entries from a permission mask on a store by authority + * + * @param storeRef + * @param authority + */ + public void deletePermissions(StoreRef storeRef, String authority); + + /** + * Remove part of a permission mask from a store + * + * @param storeRef + * @param authority + * @param perm + */ + public void deletePermission(StoreRef storeRef, String authority, PermissionReference perm); + + /** + * Remove all permission masks from a store + * + * @param storeRef + */ + public void deletePermissions(StoreRef storeRef); + + /** + * Set part of a permission mask on a store. + * + * @param storeRef + * @param authority + * @param permission + * @param allow + */ + public void setPermission(StoreRef storeRef, String authority, PermissionReference permission, boolean allow); + + /** + * Get permission masks set on a store + * @param storeRef + * @return + */ + public NodePermissionEntry getPermissions(StoreRef storeRef); } diff --git a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java index 5a9bf3d1b2..b2087d88f3 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java @@ -27,6 +27,7 @@ package org.alfresco.repo.security.permissions.impl.model; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -97,7 +98,7 @@ public class PermissionModel implements ModelDAO, InitializingBean private String model; // Aprrox 6 - default size OK - private Map permissionSets = new HashMap(); + private Map permissionSets = new HashMap(128, 1.0f); // Global permissions - default size OK private Set globalPermissions = new HashSet(); @@ -105,13 +106,13 @@ public class PermissionModel implements ModelDAO, InitializingBean private AccessStatus defaultPermission; // Cache granting permissions - private HashMap> grantingPermissions = new HashMap>(128, 1.0f); + private HashMap> grantingPermissions = new HashMap>(256, 1.0f); // Cache grantees - private HashMap> granteePermissions = new HashMap>(128, 1.0f); + private HashMap> granteePermissions = new HashMap>(256, 1.0f); // Cache the mapping of extended groups to the base - private HashMap groupsToBaseGroup = new HashMap(128, 1.0f); + private HashMap groupsToBaseGroup = new HashMap(256, 1.0f); private HashMap uniqueMap; @@ -121,9 +122,11 @@ public class PermissionModel implements ModelDAO, InitializingBean private HashMap permissionReferenceMap; - private Map> cachedTypePermissionsExposed = new HashMap>(128, 1.0f); + private Map> cachedTypePermissionsExposed = new HashMap>(256, 1.0f); - private Map> cachedTypePermissionsUnexposed = new HashMap>(128, 1.0f); + private Map> cachedTypePermissionsUnexposed = new HashMap>(256, 1.0f); + + private Collection allAspects; public PermissionModel() { @@ -226,6 +229,10 @@ public class PermissionModel implements ModelDAO, InitializingBean globalPermissions.add(globalPermission); } + + // Cache all aspect list + + allAspects = dictionaryService.getAllAspects(); } /* @@ -308,7 +315,7 @@ public class PermissionModel implements ModelDAO, InitializingBean Set permissions = cache.get(type); if (permissions == null) { - permissions = new LinkedHashSet(128, 1.0f); + permissions = new LinkedHashSet(256, 1.0f); ClassDefinition cd = dictionaryService.getClass(type); if (cd != null) { @@ -428,12 +435,12 @@ public class PermissionModel implements ModelDAO, InitializingBean private void mergeGeneralAspectPermissions(Set target, boolean exposedOnly) { - for (QName aspect : dictionaryService.getAllAspects()) + for (QName aspect : allAspects) { mergePermissions(target, aspect, exposedOnly, false); } } - + public Set getAllPermissions(NodeRef nodeRef) { return getAllPermissionsImpl(nodeService.getType(nodeRef), nodeService.getAspects(nodeRef), false); @@ -451,20 +458,14 @@ public class PermissionModel implements ModelDAO, InitializingBean private Set getAllPermissionsImpl(QName typeName, Set aspects, boolean exposedOnly) { - Set permissions = new LinkedHashSet(128, 1.0f); + Set permissions = new LinkedHashSet(256, 1.0f); + + ClassDefinition cd = dictionaryService.getClass(typeName); permissions.addAll(getAllPermissionsImpl(typeName, exposedOnly)); - ClassDefinition cd = dictionaryService.getClass(typeName); + if (cd != null) { - if (cd.isAspect()) - { - // Do not merge in all general aspects - } - else - { - mergeGeneralAspectPermissions(permissions, exposedOnly); - } Set defaultAspects = new HashSet(); for (AspectDefinition aspDef : cd.getDefaultAspects()) { @@ -500,7 +501,7 @@ public class PermissionModel implements ModelDAO, InitializingBean private Set getGrantingPermissionsImpl(PermissionReference permissionReference) { // Query the model - HashSet permissions = new HashSet(128, 1.0f); + HashSet permissions = new HashSet(256, 1.0f); permissions.add(permissionReference); for (PermissionSet ps : permissionSets.values()) { @@ -573,7 +574,7 @@ public class PermissionModel implements ModelDAO, InitializingBean private Set getGranteePermissionsImpl(PermissionReference permissionReference) { // Query the model - HashSet permissions = new HashSet(128, 1.0f); + HashSet permissions = new HashSet(256, 1.0f); permissions.add(permissionReference); for (PermissionSet ps : permissionSets.values()) { @@ -636,7 +637,7 @@ public class PermissionModel implements ModelDAO, InitializingBean private Set getAllPermissions() { - HashSet permissions = new HashSet(128, 1.0f); + HashSet permissions = new HashSet(256, 1.0f); for (PermissionSet ps : permissionSets.values()) { for (PermissionGroup pg : ps.getPermissionGroups()) @@ -817,7 +818,7 @@ public class PermissionModel implements ModelDAO, InitializingBean */ private Set getRequirementsForPermissionGroup(PermissionGroup target, RequiredPermission.On on, QName qName, Set aspectQNames) { - HashSet requiredPermissions = new HashSet(8, 1.0f); + HashSet requiredPermissions = new HashSet(16, 1.0f); if (target == null) { return requiredPermissions; @@ -960,11 +961,11 @@ public class PermissionModel implements ModelDAO, InitializingBean private void buildUniquePermissionMap() { - Set excluded = new HashSet(64, 1.0f); - uniqueMap = new HashMap(128, 1.0f); - permissionReferenceMap = new HashMap(128, 1.0f); - permissionGroupMap = new HashMap(64, 1.0f); - permissionMap = new HashMap(32, 1.0f); + Set excluded = new HashSet(128, 1.0f); + uniqueMap = new HashMap(256, 1.0f); + permissionReferenceMap = new HashMap(256, 1.0f); + permissionGroupMap = new HashMap(128, 1.0f); + permissionMap = new HashMap(64, 1.0f); for (PermissionSet ps : permissionSets.values()) { for (PermissionGroup pg : ps.getPermissionGroups()) diff --git a/source/java/org/alfresco/repo/security/permissions/noop/PermissionServiceNOOPImpl.java b/source/java/org/alfresco/repo/security/permissions/noop/PermissionServiceNOOPImpl.java index 876f83281e..7829afbc1b 100644 --- a/source/java/org/alfresco/repo/security/permissions/noop/PermissionServiceNOOPImpl.java +++ b/source/java/org/alfresco/repo/security/permissions/noop/PermissionServiceNOOPImpl.java @@ -36,6 +36,7 @@ import org.alfresco.repo.security.permissions.PermissionServiceSPI; import org.alfresco.repo.security.permissions.impl.PermissionReferenceImpl; import org.alfresco.repo.security.permissions.impl.SimpleNodePermissionEntry; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.PermissionContext; @@ -258,4 +259,31 @@ public class PermissionServiceNOOPImpl { return Collections.emptySet(); } + + public void clearPermission(StoreRef storeRef, String authority) + { + + } + + public void deletePermission(StoreRef storeRef, String authority, String permission) + { + + } + + public void deletePermissions(StoreRef storeRef) + { + + } + + public void setPermission(StoreRef storeRef, String authority, String permission, boolean allow) + { + + } + + public Set getAllSetPermissions(StoreRef storeRef) + { + return Collections.emptySet(); + } + + } diff --git a/source/java/org/alfresco/service/cmr/security/PermissionContext.java b/source/java/org/alfresco/service/cmr/security/PermissionContext.java index 3045098aa2..7cb6598e21 100644 --- a/source/java/org/alfresco/service/cmr/security/PermissionContext.java +++ b/source/java/org/alfresco/service/cmr/security/PermissionContext.java @@ -44,6 +44,8 @@ public class PermissionContext private Map additionalContext = new HashMap(); + private Long storeAcl = null; + public PermissionContext(QName type) { this.type = type; @@ -84,6 +86,16 @@ public class PermissionContext { return type; } + + public Long getStoreAcl() + { + return storeAcl; + } + + public void setStoreAcl(Long storeAcl) + { + this.storeAcl = storeAcl; + } diff --git a/source/java/org/alfresco/service/cmr/security/PermissionService.java b/source/java/org/alfresco/service/cmr/security/PermissionService.java index b19015710a..45ddc8fc51 100644 --- a/source/java/org/alfresco/service/cmr/security/PermissionService.java +++ b/source/java/org/alfresco/service/cmr/security/PermissionService.java @@ -30,6 +30,7 @@ import java.util.Set; import org.alfresco.service.Auditable; import org.alfresco.service.PublicService; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.namespace.QName; import org.apache.axis.wsdl.symbolTable.Parameters; @@ -357,4 +358,52 @@ public interface PermissionService "exactPermissionMatch" }) public Set findNodesByAssignedPermission(String authority, String permission, boolean allow, boolean includeContainingAuthorities, boolean exactPermissionMatch); + + + /** + * Add a permission mask to a store + * + * @param storeRef + * @param authority + * @param permission + * @param allow + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = { "storeRef", "authority", "permission", "allow" }) + public void setPermission(StoreRef storeRef, String authority, String permission, boolean allow); + + /** + * Remove part of a permission mask on a store + * @param storeRef + * @param authority + * @param permission + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = { "StoreRef", "authority", "permission" }) + public void deletePermission(StoreRef storeRef, String authority, String permission); + + /** + * Clear all permission masks for an authority on a store + * + * @param storeRef + * @param authority + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = { "StoreRef", "authority" }) + public void clearPermission(StoreRef storeRef, String authority); + + /** + * Remove all permission mask on a store + * + * @param storeRef + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = { "StoreRef" }) + public void deletePermissions(StoreRef storeRef); + + /** + * Get all the AccessPermissions that are set for anyone for the given node + * + * @param nodeRef - + * the reference to the node + * @return the set of allowed permissions + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = { "StoreRef" }) + public Set getAllSetPermissions(StoreRef storeRef); } \ No newline at end of file