diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index 4b804025ee..d2bb45a2c0 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -66,6 +66,25 @@ class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AssociationRefPostMethodInvocationProcessor"> + + + + + + + + + + + + diff --git a/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js b/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js index 3fcdb888af..710eed6a2e 100644 --- a/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js +++ b/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js @@ -241,7 +241,12 @@ function rm_doclist_main() { // we have to check if we have read permission on the node parent as an error will be thrown if we try to // get the evaluated properties for a linked record whose parent we do not have read permissions for - var parentReadable = (node.parent != null && node.parent.isContainer && node.parent.hasPermission("ReadRecords")); + var parentReadable; + try + { + parentReadable = (node.parent != null && node.parent.isContainer && node.parent.hasPermission("ReadRecords")); + } + catch(e){} if (!parentReadable) continue; // Get evaluated properties. diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java index 338c5ea278..5783e3bd0d 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java @@ -25,12 +25,12 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; +import org.alfresco.jlan.server.filesys.AccessDeniedException; import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceBootstrap; import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor; import org.alfresco.module.org_alfresco_module_rm.util.AlfrescoTransactionSupport; import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; -import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.dictionary.DictionaryService; @@ -129,13 +129,15 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli * @param invocation method invocation */ @SuppressWarnings("rawtypes") - public void checkClassification(final MethodInvocation invocation) + public NodeRef checkClassification(final MethodInvocation invocation) { // do in transaction - getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + return getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { - public Void execute() throws Throwable + public NodeRef execute() throws Throwable { + NodeRef result = null; + // ensure classification service has been bootstrapped if (getClassificationServiceBootstrap().isInitialised()) { @@ -160,7 +162,7 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position]; // if node exists then see if the current user has clearance - checkNode(testNodeRef); + result = checkNode(testNodeRef); } finally { @@ -174,12 +176,12 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli } } - return null; + return result; } }, true); } - private boolean validUser() + private boolean isUserValid() { boolean result = false; @@ -193,15 +195,20 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli return result; } - private void checkNode(NodeRef testNodeRef) + private NodeRef checkNode(NodeRef testNodeRef) throws AccessDeniedException { + NodeRef result = testNodeRef; + if (getNodeService().exists(testNodeRef) && getDictionaryService().isSubClass(getNodeService().getType(testNodeRef), TYPE_CONTENT) && !getContentClassificationService().hasClearance(testNodeRef)) { - // throw exception - throw new AccessDeniedException("You do not have clearance!"); + // FIXME + result = null; + //throw new AccessDeniedException("You do not have clearance!"); } + + return result; } /** @@ -210,29 +217,59 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli @Override public Object invoke(MethodInvocation invocation) throws Throwable { - boolean isValidUser = validUser(); + // FIXME + //NodeRef preInvocation = null; + Object postInvocation = null; + + boolean isUserValid = isUserValid(); // pre method invocation check - if (isValidUser) + if (isUserValid) { + // FIXME + //preInvocation = checkClassification(invocation); checkClassification(invocation); } // method proceed - Object result = invocation.proceed(); + postInvocation = invocation.proceed(); // post method invocation processing - if (isValidUser && result != null) + if (isUserValid && postInvocation != null) { - Class clazz = result.getClass(); - BasePostMethodInvocationProcessor processor = processors.get(clazz); + Class clazz = postInvocation.getClass(); + BasePostMethodInvocationProcessor processor = getProcessor(processors, clazz); + if (processor != null) { - processor.process(result); + postInvocation = processor.process(postInvocation); } else { - LOG.warn("No post method invocation processor found for '" + clazz + "'."); + LOG.debug("No post method invocation processor found for '" + clazz + "'."); + } + } + + return postInvocation; + } + + /** + * Gets the processor from the available processors + * + * @param processors Available processors + * @param clazz The runtime class of the post invocation object + * @return The suitable processor for the given class + */ + private BasePostMethodInvocationProcessor getProcessor(Map, BasePostMethodInvocationProcessor> processors, Class clazz) + { + BasePostMethodInvocationProcessor result = null; + + for (Map.Entry, BasePostMethodInvocationProcessor> processor : processors.entrySet()) + { + if (processor.getKey().isAssignableFrom(clazz)) + { + result = processor.getValue(); + break; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java index 85b5243636..e2cebd6317 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java @@ -51,11 +51,11 @@ public class AssociationRefPostMethodInvocationProcessor extends BasePostMethodI AssociationRef associationRef = ((AssociationRef) object); NodeRef sourceRef = associationRef.getSourceRef(); - check(sourceRef); + NodeRef filteredSource = filter(sourceRef); NodeRef targetRef = associationRef.getTargetRef(); - check(targetRef); + NodeRef filteredTarget = filter(targetRef); - return object; + return (filteredSource == null || filteredTarget == null) ? null : object; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java index f66d0d0b94..52af2f95b4 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -18,10 +18,10 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import org.alfresco.model.ContentModel; +import static org.alfresco.model.ContentModel.TYPE_CONTENT; + import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor; -import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -110,6 +110,13 @@ public abstract class BasePostMethodInvocationProcessor this.contentClassificationService = contentClassificationService; } + /** + * Gets the class name + * + * @return The class name + */ + public abstract Class getClassName(); + /** * Performs checks on the given object and throws exception if not all checks pass * @@ -118,13 +125,6 @@ public abstract class BasePostMethodInvocationProcessor */ public abstract T process(T object); - /** - * Gets the class name - * - * @return The class name - */ - public abstract Class getClassName(); - /** * Registers the post method invocation processors */ @@ -134,24 +134,24 @@ public abstract class BasePostMethodInvocationProcessor } /** - * Performs checks on the given node: - * - *
    - *
  • Does the node exist
  • - *
  • Is it a content
  • - *
  • Is the logged in user cleared to see the it.
  • - *
+ * Filters the node if the give node reference exist and it is a + * content but the logged in user is not cleared to see the it. * * @param nodeRef Node reference + * @return null if the give node reference has been + * filtered, the node reference itself otherwise */ - protected void check(NodeRef nodeRef) + protected NodeRef filter(NodeRef nodeRef) { + NodeRef filter = nodeRef; + if (getNodeService().exists(nodeRef) && - getDictionaryService().isSubClass(getNodeService().getType(nodeRef), ContentModel.TYPE_CONTENT) && + getDictionaryService().isSubClass(getNodeService().getType(nodeRef), TYPE_CONTENT) && !getContentClassificationService().hasClearance(nodeRef)) { - // throw exception - throw new AccessDeniedException("You do not have clearance!"); + filter = null; } + + return filter; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java index c868c34ea2..9fa6b263d0 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java @@ -51,11 +51,11 @@ public class ChildAssociationRefPostMethodInvocationProcessor extends BasePostMe ChildAssociationRef childAssociationRef = ((ChildAssociationRef) object); NodeRef childRef = childAssociationRef.getChildRef(); - check(childRef); + NodeRef filteredChildRef = filter(childRef); NodeRef parentRef = childAssociationRef.getParentRef(); - check(parentRef); + NodeRef filteredParentRef = filter(parentRef); - return object; + return (filteredChildRef == null || filteredParentRef == null) ? null : object; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..b65bd326f2 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.Collection; +import java.util.Iterator; + +import org.alfresco.service.cmr.repository.AssociationRef; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.collections.CollectionUtils; +import org.alfresco.util.collections.Filter; + +/** + * Collection Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public abstract class CollectionPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** Node ref post method invocation processor */ + private NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor; + + /** Association post method invocation processor */ + private AssociationRefPostMethodInvocationProcessor associationRefPostMethodInvocationProcessor; + + /** Child association post method invocation processor */ + private ChildAssociationRefPostMethodInvocationProcessor childAssociationRefPostMethodInvocationProcessor; + + /** + * @return the nodeRefPostMethodInvocationProcessor + */ + protected NodeRefPostMethodInvocationProcessor getNodeRefPostMethodInvocationProcessor() + { + return this.nodeRefPostMethodInvocationProcessor; + } + + /** + * @return the associationRefPostMethodInvocationProcessor + */ + protected AssociationRefPostMethodInvocationProcessor getAssociationRefPostMethodInvocationProcessor() + { + return this.associationRefPostMethodInvocationProcessor; + } + + /** + * @return the childAssociationRefPostMethodInvocationProcessor + */ + protected ChildAssociationRefPostMethodInvocationProcessor getChildAssociationRefPostMethodInvocationProcessor() + { + return this.childAssociationRefPostMethodInvocationProcessor; + } + + /** + * @param nodeRefPostMethodInvocationProcessor the nodeRefPostMethodInvocationProcessor to set + */ + public void setNodeRefPostMethodInvocationProcessor(NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor) + { + this.nodeRefPostMethodInvocationProcessor = nodeRefPostMethodInvocationProcessor; + } + + /** + * @param associationRefPostMethodInvocationProcessor the associationRefPostMethodInvocationProcessor to set + */ + public void setAssociationRefPostMethodInvocationProcessor(AssociationRefPostMethodInvocationProcessor associationRefPostMethodInvocationProcessor) + { + this.associationRefPostMethodInvocationProcessor = associationRefPostMethodInvocationProcessor; + } + + /** + * @param childAssociationRefPostMethodInvocationProcessor the childAssociationRefPostMethodInvocationProcessor to set + */ + public void setChildAssociationRefPostMethodInvocationProcessor(ChildAssociationRefPostMethodInvocationProcessor childAssociationRefPostMethodInvocationProcessor) + { + this.childAssociationRefPostMethodInvocationProcessor = childAssociationRefPostMethodInvocationProcessor; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public T process(T object) + { + Object result = object; + + Collection collection = ((Collection) object); + if (!collection.isEmpty()) + { + Iterator iterator = collection.iterator(); + if (iterator.hasNext()) + { + Class clazz = iterator.next().getClass(); + if (NodeRef.class.isAssignableFrom(clazz)) + { + result = processNodeRef(collection, iterator); + } + + if (AssociationRef.class.isAssignableFrom(clazz)) + { + result = processAssociationRef(collection, iterator); + } + + if (ChildAssociationRef.class.isAssignableFrom(clazz)) + { + result = processChildAssociationRef(collection, iterator); + } + } + } + + return (T) result; + } + + /** + * Processes a {@link NodeRef} collection + * + * @param collection The collection to process + * @return The processed collection + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Collection processNodeRef(Collection collection, Iterator iterator) + { + CollectionUtils.filter(collection, new Filter() + { + @Override + public Boolean apply(NodeRef nodeRef) + { + return getNodeRefPostMethodInvocationProcessor().process(nodeRef) != null; + } + }); + + return collection; + } + + /** + * Processes a {@link AssociationRef} collection + * + * @param collection The collection to process + * @return The processed collection + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Collection processAssociationRef(Collection collection, Iterator iterator) + { + CollectionUtils.filter(collection, new Filter() + { + @Override + public Boolean apply(AssociationRef associationRef) + { + return getAssociationRefPostMethodInvocationProcessor().process(associationRef) != null; + } + }); + + return collection; + } + + /** + * Processes a {@link ChildAssociationRef} collection + * + * @param collection The collection to process + * @return The processed collection + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Collection processChildAssociationRef(Collection collection, Iterator iterator) + { + CollectionUtils.filter(collection, new Filter() + { + @Override + public Boolean apply(ChildAssociationRef childAssociationRef) + { + return getChildAssociationRefPostMethodInvocationProcessor().process(childAssociationRef) != null; + } + }); + + return collection; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..4962eada3f --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.List; + +/** + * List Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class ListPostMethodInvocationProcessor extends CollectionPostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @SuppressWarnings("rawtypes") + @Override + public Class getClassName() + { + return List.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @Override + public T process(T object) + { + return super.process(object); + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java index 8d78d7e4c6..11654de8a5 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java @@ -47,8 +47,6 @@ public class NodeRefPostMethodInvocationProcessor extends BasePostMethodInvocati { mandatory("object", object); - check(((NodeRef) object)); - - return object; + return filter((NodeRef) object) == null ? null : object; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..6fb47e4516 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.Set; + +/** + * Set Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class SetPostMethodInvocationProcessor extends CollectionPostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @SuppressWarnings("rawtypes") + @Override + public Class getClassName() + { + return Set.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @Override + public T process(T object) + { + return super.process(object); + } +}