diff --git a/config/alfresco/authority-services-context.xml b/config/alfresco/authority-services-context.xml index fb6bd7301d..1c575d1766 100644 --- a/config/alfresco/authority-services-context.xml +++ b/config/alfresco/authority-services-context.xml @@ -12,7 +12,7 @@ - + @@ -46,6 +46,9 @@ + + + diff --git a/config/alfresco/policy-context.xml b/config/alfresco/policy-context.xml index e3dd35c25f..dd1e674975 100644 --- a/config/alfresco/policy-context.xml +++ b/config/alfresco/policy-context.xml @@ -68,4 +68,8 @@ + + + + diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml index 5666e32b7d..194dc9c0a8 100644 --- a/config/alfresco/public-services-security-context.xml +++ b/config/alfresco/public-services-security-context.xml @@ -105,9 +105,10 @@ + - + @@ -115,6 +116,8 @@ + + diff --git a/source/java/org/alfresco/repo/domain/permissions/FixedAclUpdater.java b/source/java/org/alfresco/repo/domain/permissions/FixedAclUpdater.java index 370c4b0643..7e7f386656 100644 --- a/source/java/org/alfresco/repo/domain/permissions/FixedAclUpdater.java +++ b/source/java/org/alfresco/repo/domain/permissions/FixedAclUpdater.java @@ -25,6 +25,8 @@ */ package org.alfresco.repo.domain.permissions; +import static org.apache.commons.lang3.BooleanUtils.toBoolean; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -41,8 +43,13 @@ import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback; import org.alfresco.repo.lock.JobLockService; import org.alfresco.repo.lock.JobLockService.JobLockRefreshCallback; import org.alfresco.repo.lock.LockAcquisitionException; +import org.alfresco.repo.policy.ClassPolicyDelegate; +import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.security.permissions.PermissionServicePolicies; +import org.alfresco.repo.security.permissions.PermissionServicePolicies.OnInheritPermissionsDisabled; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.TransactionListenerAdapter; import org.alfresco.service.cmr.repository.NodeRef; @@ -50,6 +57,7 @@ import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.Pair; +import org.alfresco.util.PolicyIgnoreUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; @@ -83,6 +91,10 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli private int maxItemBatchSize = 100; private int numThreads = 4; + private ClassPolicyDelegate onInheritPermissionsDisabledDelegate; + private PolicyComponent policyComponent; + private PolicyIgnoreUtil policyIgnoreUtil; + public void setNumThreads(int numThreads) { this.numThreads = numThreads; @@ -123,6 +135,21 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli { this.lockTimeToLive = lockTimeToLive; this.lockRefreshTime = lockTimeToLive / 2; + } + + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + + public void setPolicyIgnoreUtil(PolicyIgnoreUtil policyIgnoreUtil) + { + this.policyIgnoreUtil = policyIgnoreUtil; + } + + public void init() + { + onInheritPermissionsDisabledDelegate = policyComponent.registerClassPolicy(PermissionServicePolicies.OnInheritPermissionsDisabled.class); } private class GetNodesWithAspects @@ -249,6 +276,14 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli nodeDAO.removeNodeAspects(nodeId, aspects); nodeDAO.removeNodeProperties(nodeId, PENDING_FIX_ACL_ASPECT_PROPS); + + if (!policyIgnoreUtil.ignorePolicy(nodeRef)) + { + boolean transformedToAsyncOperation = toBoolean((Boolean) AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY)); + + OnInheritPermissionsDisabled onInheritPermissionsDisabledPolicy = onInheritPermissionsDisabledDelegate.get(ContentModel.TYPE_BASE); + onInheritPermissionsDisabledPolicy.onInheritPermissionsDisabled(nodeRef, transformedToAsyncOperation); + } if (log.isDebugEnabled()) { diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java b/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java index dfab0dfb4a..6689754732 100644 --- a/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java +++ b/source/java/org/alfresco/repo/security/authority/AuthorityServiceImpl.java @@ -25,32 +25,39 @@ */ package org.alfresco.repo.security.authority; -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.query.PagingRequest; -import org.alfresco.query.PagingResults; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.permissions.PermissionServiceSPI; -import org.alfresco.repo.security.person.UserNameMatcher; -import org.alfresco.repo.tenant.TenantService; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.service.cmr.security.AuthorityService; -import org.alfresco.service.cmr.security.AuthorityType; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.util.Pair; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.extensions.surf.util.ParameterCheck; +import static org.alfresco.service.cmr.security.PermissionService.GROUP_PREFIX; + +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.alfresco.model.ContentModel; +import org.alfresco.query.PagingRequest; +import org.alfresco.query.PagingResults; +import org.alfresco.repo.policy.ClassPolicyDelegate; +import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authority.AuthorityServicePolicies.OnAuthorityAddedToGroup; +import org.alfresco.repo.security.authority.AuthorityServicePolicies.OnAuthorityRemovedFromGroup; +import org.alfresco.repo.security.authority.AuthorityServicePolicies.OnGroupDeleted; +import org.alfresco.repo.security.permissions.PermissionServiceSPI; +import org.alfresco.repo.security.person.UserNameMatcher; +import org.alfresco.repo.tenant.TenantService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.util.Pair; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.extensions.surf.util.ParameterCheck; /** * The default implementation of the authority service. @@ -78,7 +85,12 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean private Set guestSet = Collections.singleton(PermissionService.GUEST_AUTHORITY); private Set allSet = Collections.singleton(PermissionService.ALL_AUTHORITIES); private Set adminGroups = Collections.emptySet(); - private Set guestGroups = Collections.emptySet(); + private Set guestGroups = Collections.emptySet(); + + private ClassPolicyDelegate onAuthorityAddedToGroups; + private ClassPolicyDelegate onAuthorityRemovedFromGroup; + private ClassPolicyDelegate onGroupDeletedDelegate; + private PolicyComponent policyComponent; public AuthorityServiceImpl() { @@ -123,6 +135,18 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean public void setGuestGroups(Set guestGroups) { this.guestGroups = guestGroups; + } + + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + + public void init() + { + onAuthorityAddedToGroups = policyComponent.registerClassPolicy(AuthorityServicePolicies.OnAuthorityAddedToGroup.class); + onAuthorityRemovedFromGroup = policyComponent.registerClassPolicy(AuthorityServicePolicies.OnAuthorityRemovedFromGroup.class); + onGroupDeletedDelegate = policyComponent.registerClassPolicy(AuthorityServicePolicies.OnGroupDeleted.class); } @Override @@ -460,7 +484,13 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean */ public void addAuthority(Collection parentNames, String childName) { - authorityDAO.addAuthority(parentNames, childName); + authorityDAO.addAuthority(parentNames, childName); + + OnAuthorityAddedToGroup policy = onAuthorityAddedToGroups.get(ContentModel.TYPE_AUTHORITY); + for (String parentGroup : parentNames) + { + policy.onAuthorityAddedToGroup(parentGroup, childName); + } } private boolean containsMatch(Set names, String name) @@ -537,7 +567,18 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean } } authorityDAO.deleteAuthority(name); - permissionServiceSPI.deletePermissions(name); + permissionServiceSPI.deletePermissions(name); + + if (isGroup(type)) + { + OnGroupDeleted onGroupDelete = onGroupDeletedDelegate.get(ContentModel.TYPE_AUTHORITY); + onGroupDelete.onGroupDeleted(name, cascade); + } + } + + private boolean isGroup(AuthorityType authorityType) + { + return AuthorityType.GROUP == authorityType || AuthorityType.EVERYONE == authorityType; } /** @@ -583,7 +624,10 @@ public class AuthorityServiceImpl implements AuthorityService, InitializingBean @Override public void removeAuthority(String parentName, String childName) { - authorityDAO.removeAuthority(parentName, childName); + authorityDAO.removeAuthority(parentName, childName); + + OnAuthorityRemovedFromGroup policy = onAuthorityRemovedFromGroup.get(ContentModel.TYPE_AUTHORITY); + policy.onAuthorityRemovedFromGroup(parentName, childName); } /** diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityServicePolicies.java b/source/java/org/alfresco/repo/security/authority/AuthorityServicePolicies.java new file mode 100644 index 0000000000..bd29d1d61f --- /dev/null +++ b/source/java/org/alfresco/repo/security/authority/AuthorityServicePolicies.java @@ -0,0 +1,87 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2017 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 . + * #L% + */ +package org.alfresco.repo.security.authority; + +import org.alfresco.repo.policy.ClassPolicy; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +/** + * Policies for AuthorityService + * + * @author cpopa + * + */ +public interface AuthorityServicePolicies +{ + /** + * Policy invoked when an authority is added to a group + */ + public interface OnAuthorityAddedToGroup extends ClassPolicy + { + public static final QName QNAME = QName.createQName(NamespaceService.ALFRESCO_URI, "onAuthorityAddedToGroup"); + + /** + * An authority is added in a group + * + * @param parentGroup the group into which the authority is added + * @param childAuthority the authority being added to the groups + */ + public void onAuthorityAddedToGroup(String parentGroup, String childAuthority); + } + + /** + * Policy invoked when an authority is removed from a group + */ + public interface OnAuthorityRemovedFromGroup extends ClassPolicy + { + public static final QName QNAME = QName.createQName(NamespaceService.ALFRESCO_URI, "onAuthorityRemovedFromGroup"); + + /** + * An authority was removed from a group + * + * @param parentGroup the group from which the authority is removed + * @param childAuthority the authority being removed from the group + */ + public void onAuthorityRemovedFromGroup(String parentGroup, String childAuthority); + } + + /** + * Policy invoked when a group is deleted + */ + public interface OnGroupDeleted extends ClassPolicy + { + public static final QName QNAME = QName.createQName(NamespaceService.ALFRESCO_URI, "onGroupDeleted"); + + /** + * A group has been deleted + * + * @param groupName the group being deleted + * @param cascade whether the deletion is cascaded to child authorities + */ + public void onGroupDeleted(String groupName, boolean cascade); + } +} diff --git a/source/java/org/alfresco/repo/security/permissions/PermissionServicePolicies.java b/source/java/org/alfresco/repo/security/permissions/PermissionServicePolicies.java new file mode 100644 index 0000000000..7681940ffa --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/PermissionServicePolicies.java @@ -0,0 +1,106 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2017 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 . + * #L% + */ +package org.alfresco.repo.security.permissions; + +import org.alfresco.repo.policy.ClassPolicy; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +/** + * Policies for PermissionService + * + * @author cpopa + * + */ +public interface PermissionServicePolicies +{ + /** + * Policy invoked when a permission is granted to an authority for a specific node + */ + public interface OnGrantLocalPermission extends ClassPolicy + { + public static final QName QNAME = QName.createQName(NamespaceService.ALFRESCO_URI, "onGrantLocalPermission"); + + /** + * A permission was granted to an authority for a specific node + * + * @param nodeRef the node on which the permission is granted + * @param authority the authority being granted the permission + * @param permission the permission at question + */ + public void onGrantLocalPermission(NodeRef nodeRef, String authority, String permission); + } + + /** + * Policy invoked when a permission is revoked from an authority for a specific node + */ + public interface OnRevokeLocalPermission extends ClassPolicy + { + public static final QName QNAME = QName.createQName(NamespaceService.ALFRESCO_URI, "onRevokeLocalPermission"); + + /** + * A permission was revoked from an authority for a specific node + * + * @param nodeRef the node from which the permission is revoked + * @param authority the authority being revoked the permission + * @param permission the permission at question + */ + public void onRevokeLocalPermission(NodeRef nodeRef, String authority, String permission); + } + + /** + * Policy invoked when permission inheritance is enabled for a specific node + */ + public interface OnInheritPermissionsEnabled extends ClassPolicy + { + public static final QName QNAME = QName.createQName(NamespaceService.ALFRESCO_URI, "onInheritPermissionsEnabled"); + + /** + * Permission inheritance was enabled + * + * @param nodeRef the node for which the inheritance is enabled + */ + public void onInheritPermissionsEnabled(NodeRef nodeRef); + + } + + /** + * Policy invoked when permission inheritance is disabled for a specific node (sync or async mode) + */ + public interface OnInheritPermissionsDisabled extends ClassPolicy + { + public static final QName QNAME = QName.createQName(NamespaceService.ALFRESCO_URI, "onInheritPermissionsDisabled"); + + /** + * Permission inheritance was disabled + * + * @param nodeRef the node for which the inheritance is disabled + * @param async whether the operation has been done in asynchronous mode, thus it may not be finished yet + */ + public void onInheritPermissionsDisabled(NodeRef nodeRef, boolean async); + } +} 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 b842f1b452..63e27d97d7 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java @@ -25,70 +25,77 @@ */ package org.alfresco.repo.security.permissions.impl; -import java.io.Serializable; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import net.sf.acegisecurity.Authentication; -import net.sf.acegisecurity.GrantedAuthority; -import net.sf.acegisecurity.providers.dao.User; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.cache.SimpleCache; -import org.alfresco.repo.domain.permissions.AclDAO; -import org.alfresco.repo.node.db.traitextender.NodeServiceTrait; -import org.alfresco.repo.domain.permissions.FixedAclUpdater; -import org.alfresco.repo.policy.JavaBehaviour; -import org.alfresco.repo.policy.PolicyComponent; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; -import org.alfresco.repo.security.authority.AuthorityServiceImpl; -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.AccessControlListProperties; -import org.alfresco.repo.security.permissions.DynamicAuthority; -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.PermissionServiceSPI; -import org.alfresco.repo.security.permissions.impl.traitextender.PermissionServiceExtension; -import org.alfresco.repo.security.permissions.impl.traitextender.PermissionServiceTrait; -import org.alfresco.repo.tenant.TenantService; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; -import org.alfresco.repo.version.Version2Model; -import org.alfresco.repo.version.VersionModel; -import org.alfresco.repo.version.common.VersionUtil; -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; -import org.alfresco.service.cmr.security.OwnableService; -import org.alfresco.service.cmr.security.PermissionContext; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.traitextender.AJExtender; -import org.alfresco.traitextender.Extend; -import org.alfresco.traitextender.ExtendedTrait; -import org.alfresco.traitextender.Extensible; -import org.alfresco.traitextender.AJProxyTrait; -import org.alfresco.traitextender.Trait; -import org.alfresco.util.EqualsHelper; -import org.alfresco.util.Pair; -import org.alfresco.util.PropertyCheck; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.context.ApplicationEvent; -import org.springframework.extensions.surf.util.AbstractLifecycleBean; +import static org.apache.commons.lang3.BooleanUtils.toBoolean; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.GrantedAuthority; +import net.sf.acegisecurity.providers.dao.User; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.domain.permissions.AclDAO; +import org.alfresco.repo.domain.permissions.FixedAclUpdater; +import org.alfresco.repo.policy.ClassPolicyDelegate; +import org.alfresco.repo.policy.JavaBehaviour; +import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.security.authority.AuthorityServiceImpl; +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.AccessControlListProperties; +import org.alfresco.repo.security.permissions.DynamicAuthority; +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.PermissionServicePolicies; +import org.alfresco.repo.security.permissions.PermissionServicePolicies.OnGrantLocalPermission; +import org.alfresco.repo.security.permissions.PermissionServicePolicies.OnInheritPermissionsDisabled; +import org.alfresco.repo.security.permissions.PermissionServicePolicies.OnInheritPermissionsEnabled; +import org.alfresco.repo.security.permissions.PermissionServicePolicies.OnRevokeLocalPermission; +import org.alfresco.repo.security.permissions.PermissionServiceSPI; +import org.alfresco.repo.security.permissions.impl.traitextender.PermissionServiceExtension; +import org.alfresco.repo.security.permissions.impl.traitextender.PermissionServiceTrait; +import org.alfresco.repo.tenant.TenantService; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.repo.version.Version2Model; +import org.alfresco.repo.version.VersionModel; +import org.alfresco.repo.version.common.VersionUtil; +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; +import org.alfresco.service.cmr.security.OwnableService; +import org.alfresco.service.cmr.security.PermissionContext; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.traitextender.AJProxyTrait; +import org.alfresco.traitextender.Extend; +import org.alfresco.traitextender.ExtendedTrait; +import org.alfresco.traitextender.Extensible; +import org.alfresco.traitextender.Trait; +import org.alfresco.util.EqualsHelper; +import org.alfresco.util.Pair; +import org.alfresco.util.PolicyIgnoreUtil; +import org.alfresco.util.PropertyCheck; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationEvent; +import org.springframework.extensions.surf.util.AbstractLifecycleBean; /** * The Alfresco implementation of a permissions service against our APIs for the permissions model and permissions @@ -161,7 +168,14 @@ public class PermissionServiceImpl extends AbstractLifecycleBean implements Perm protected boolean anyDenyDenies = false; - private final ExtendedTrait permissionServiceTrait; + private final ExtendedTrait permissionServiceTrait; + + private ClassPolicyDelegate onGrantLocalPermissionDelegate; + private ClassPolicyDelegate onRevokeLocalPermissionDelegate; + private ClassPolicyDelegate onInheritPermissionsEnabledDelegate; + private ClassPolicyDelegate onInheritPermissionsDisabledDelegate; + + private PolicyIgnoreUtil policyIgnoreUtil; /** * Standard spring construction. @@ -322,6 +336,11 @@ public class PermissionServiceImpl extends AbstractLifecycleBean implements Perm public void setPolicyComponent(PolicyComponent policyComponent) { this.policyComponent = policyComponent; + } + + public void setPolicyIgnoreUtil(PolicyIgnoreUtil policyIgnoreUtil) + { + this.policyIgnoreUtil = policyIgnoreUtil; } /** @@ -385,7 +404,12 @@ public class PermissionServiceImpl extends AbstractLifecycleBean implements Perm policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onMoveNode"), ContentModel.TYPE_BASE, new JavaBehaviour(this, "onMoveNode")); policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateChildAssociation"), ContentModel.TYPE_AUTHORITY_CONTAINER, new JavaBehaviour(this, "onCreateChildAssociation")); - policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteChildAssociation"), ContentModel.TYPE_AUTHORITY_CONTAINER, new JavaBehaviour(this, "beforeDeleteChildAssociation")); + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteChildAssociation"), ContentModel.TYPE_AUTHORITY_CONTAINER, new JavaBehaviour(this, "beforeDeleteChildAssociation")); + + onGrantLocalPermissionDelegate = policyComponent.registerClassPolicy(PermissionServicePolicies.OnGrantLocalPermission.class); + onRevokeLocalPermissionDelegate = policyComponent.registerClassPolicy(PermissionServicePolicies.OnRevokeLocalPermission.class); + onInheritPermissionsEnabledDelegate = policyComponent.registerClassPolicy(PermissionServicePolicies.OnInheritPermissionsEnabled.class); + onInheritPermissionsDisabledDelegate = policyComponent.registerClassPolicy(PermissionServicePolicies.OnInheritPermissionsDisabled.class); } // @@ -978,7 +1002,9 @@ public class PermissionServiceImpl extends AbstractLifecycleBean implements Perm public void deletePermissions(NodeRef nodeRef) { permissionsDaoComponent.deletePermissions(tenantService.getName(nodeRef)); - accessCache.clear(); + accessCache.clear(); + + invokeUpdateLocalPermissionsPolicy(nodeRef, null, null, false); } @Override @@ -1005,7 +1031,26 @@ public class PermissionServiceImpl extends AbstractLifecycleBean implements Perm protected void deletePermission(NodeRef nodeRef, String authority, PermissionReference perm) { permissionsDaoComponent.deletePermission(tenantService.getName(nodeRef), authority, perm); - accessCache.clear(); + accessCache.clear(); + + invokeUpdateLocalPermissionsPolicy(nodeRef, authority, perm.getName(), false); + } + + private void invokeUpdateLocalPermissionsPolicy(NodeRef nodeRef, String authority, String permission, boolean grantPermission) + { + if (!policyIgnoreUtil.ignorePolicy(nodeRef)) + { + if (grantPermission) + { + OnGrantLocalPermission grantPermPolicy = onGrantLocalPermissionDelegate.get(nodeService.getType(nodeRef)); + grantPermPolicy.onGrantLocalPermission(nodeRef, authority, permission); + } + else + { + OnRevokeLocalPermission revokePermPolicy = onRevokeLocalPermissionDelegate.get(nodeService.getType(nodeRef)); + revokePermPolicy.onRevokeLocalPermission(nodeRef, authority, permission); + } + } } @Override @@ -1019,7 +1064,9 @@ public class PermissionServiceImpl extends AbstractLifecycleBean implements Perm protected void setPermission(NodeRef nodeRef, String authority, PermissionReference perm, boolean allow) { permissionsDaoComponent.setPermission(tenantService.getName(nodeRef), authority, perm, allow); - accessCache.clear(); + accessCache.clear(); + + invokeUpdateLocalPermissionsPolicy(nodeRef, authority, perm.getName(), allow); } @Override @@ -1046,7 +1093,9 @@ public class PermissionServiceImpl extends AbstractLifecycleBean implements Perm { NodeRef actualRef = tenantService.getName(nodeRef); permissionsDaoComponent.setInheritParentPermissions(actualRef, inheritParentPermissions); - accessCache.clear(); + accessCache.clear(); + + invokeOnPermissionsInheritedPolicy(nodeRef, inheritParentPermissions, false); } @Override @@ -1060,20 +1109,40 @@ public class PermissionServiceImpl extends AbstractLifecycleBean implements Perm AlfrescoTransactionSupport.bindResource(FixedAclUpdater.FIXED_ACL_ASYNC_CALL_KEY, true); permissionsDaoComponent.setInheritParentPermissions(actualRef, inheritParentPermissions); //check if asynchronous call was required - Boolean asyncCallRequired = (Boolean) AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY); - if (asyncCallRequired != null && asyncCallRequired) + boolean asyncCallRequired = toBoolean((Boolean) AlfrescoTransactionSupport.getResource(FixedAclUpdater.FIXED_ACL_ASYNC_REQUIRED_KEY)); + if (asyncCallRequired) { //after transaction is committed FixedAclUpdater will be started in a new thread to process pending nodes - AlfrescoTransactionSupport.bindListener(fixedAclUpdater); - } + AlfrescoTransactionSupport.bindListener(fixedAclUpdater); + } + invokeOnPermissionsInheritedPolicy(nodeRef, inheritParentPermissions, asyncCallRequired); } else { //regular method call - permissionsDaoComponent.setInheritParentPermissions(actualRef, inheritParentPermissions); + permissionsDaoComponent.setInheritParentPermissions(actualRef, inheritParentPermissions); + + invokeOnPermissionsInheritedPolicy(nodeRef, inheritParentPermissions, false); } accessCache.clear(); + } + + private void invokeOnPermissionsInheritedPolicy(NodeRef nodeRef, final boolean inheritParentPermissions, boolean async) + { + if (!policyIgnoreUtil.ignorePolicy(nodeRef)) + { + if (inheritParentPermissions) + { + OnInheritPermissionsEnabled onInheritEnabledPolicy = onInheritPermissionsEnabledDelegate.get(ContentModel.TYPE_BASE); + onInheritEnabledPolicy.onInheritPermissionsEnabled(nodeRef); + } + else + { + OnInheritPermissionsDisabled onInheritDisabledPolicy = onInheritPermissionsDisabledDelegate.get(ContentModel.TYPE_BASE); + onInheritDisabledPolicy.onInheritPermissionsDisabled(nodeRef, async); + } + } } /** diff --git a/source/java/org/alfresco/util/PolicyIgnoreUtil.java b/source/java/org/alfresco/util/PolicyIgnoreUtil.java new file mode 100644 index 0000000000..6c31b7b284 --- /dev/null +++ b/source/java/org/alfresco/util/PolicyIgnoreUtil.java @@ -0,0 +1,66 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2017 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 . + * #L% + */ +package org.alfresco.util; + +import java.util.Collections; +import java.util.Set; + +import org.alfresco.repo.tenant.TenantService; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Utility class which checks whether a node is in a store on which policies should not be applied(e.g. archive://SpacesStore) + * + * @author cpopa + * + */ +public class PolicyIgnoreUtil +{ + private TenantService tenantService; + private Set storesToIgnorePolicies = Collections.emptySet(); + + public void setStoresToIgnorePolicies(Set storesToIgnorePolicies) + { + this.storesToIgnorePolicies = storesToIgnorePolicies; + } + + public void setTenantService(TenantService tenantService) + { + this.tenantService = tenantService; + } + + /** + * Checks whether the node is in a store on which policies should not be applied. + * + * @param nodeRef + * node to check if the policy can be run or not + * @return true if the nodeRef is part of a store which should be ignored when invoking policies(e.g. archive://SpacesStore) + */ + public boolean ignorePolicy(NodeRef nodeRef) + { + return (storesToIgnorePolicies.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString())); + } +}