From 3772764f8e020bb348891d02422e01386332b953 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Sat, 20 Jun 2015 18:42:32 +0000 Subject: [PATCH] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106639 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 24 +- .../SecurityClearanceServiceImpl.java | 2 +- .../ClassificationMethodInterceptor.java | 375 ++++++------------ ...icationMethodInterceptorPostProcessor.java | 18 +- ...AbstractPostMethodInvocationProcessor.java | 29 +- .../BasePostMethodInvocationProcessor.java | 38 +- ...ationRefPostMethodInvocationProcessor.java | 2 +- ...llectionPostMethodInvocationProcessor.java | 28 +- ...ava => PostMethodInvocationProcessor.java} | 51 ++- .../PreMethodInvocationProcessor.java | 173 ++++++++ ...PostMethodInvocationProcessorUnitTest.java | 6 - 11 files changed, 407 insertions(+), 339 deletions(-) rename rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/{PostMethodInvocationProcessorRegistry.java => PostMethodInvocationProcessor.java} (59%) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java 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 1a5c7bff55..aeb2f39e64 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 @@ -35,24 +35,30 @@ + + + + + + + class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor"> + + - - + class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptorPostProcessor" /> - + abstract="true" + init-method="register"> - + . - */ -package org.alfresco.module.org_alfresco_module_rm.classification.interceptor; - -import static org.alfresco.model.ContentModel.TYPE_CONTENT; -import static org.codehaus.plexus.util.StringUtils.isNotBlank; - -import java.lang.reflect.Method; - -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.classification.interceptor.processor.PostMethodInvocationProcessorRegistry; -import org.alfresco.module.org_alfresco_module_rm.util.AlfrescoTransactionSupport; -import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.GUID; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.log4j.Logger; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; - -/** - * Classification method interceptor - * - * @author Roy Wetherall - * @since 3.0 - */ -public class ClassificationMethodInterceptor implements MethodInterceptor, ApplicationContextAware -{ - /** Logger */ - private static Logger LOG = Logger.getLogger(ClassificationMethodInterceptor.class); - - private static final String KEY_PROCESSING = GUID.generate(); - - /** application context */ - private ApplicationContext applicationContext; - - /** - * @param applicationContext application context - * @throws BeansException - */ - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException - { - this.applicationContext = applicationContext; - } - - protected AuthenticationUtil getAuthenticationUtil() - { - return (AuthenticationUtil)applicationContext.getBean("rm.authenticationUtil"); - } - - /** - * @return {@link ContentClassificationService} content classification service - */ - protected ContentClassificationService getContentClassificationService() - { - return (ContentClassificationService)applicationContext.getBean("contentClassificationService"); - } - - protected AlfrescoTransactionSupport getAlfrescoTransactionSupport() - { - return (AlfrescoTransactionSupport)applicationContext.getBean("rm.alfrescoTransactionSupport"); - } - - protected RetryingTransactionHelper getRetryingTransactionHelper() - { - return ((TransactionService)applicationContext.getBean("transactionService")).getRetryingTransactionHelper(); - } - - protected ClassificationServiceBootstrap getClassificationServiceBootstrap() - { - return (ClassificationServiceBootstrap)applicationContext.getBean("classificationServiceBootstrap"); - } - - protected NodeService getNodeService() - { - return (NodeService)applicationContext.getBean("dbNodeService"); - } - - protected DictionaryService getDictionaryService() - { - return (DictionaryService)applicationContext.getBean("dictionaryService"); - } - - protected PostMethodInvocationProcessorRegistry getPostMethodInvocationProcessorRegistry() - { - return (PostMethodInvocationProcessorRegistry)applicationContext.getBean("postMethodInvocationProcessorRegistry"); - } - - /** - * Check that the current user is cleared to see the items passed as parameters to the current - * method invocation. - * - * @param invocation method invocation - */ - @SuppressWarnings("rawtypes") - public NodeRef checkClassification(final MethodInvocation invocation) - { - // do in transaction - return getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() - { - public NodeRef execute() throws Throwable - { - NodeRef result = null; - - // ensure classification service has been bootstrapped - if (getClassificationServiceBootstrap().isInitialised()) - { - // check that we are not already processing a classification check - Object value = getAlfrescoTransactionSupport().getResource(KEY_PROCESSING); - if (value == null) - { - Method method = invocation.getMethod(); - Class[] params = method.getParameterTypes(); - - int position = 0; - for (Class param : params) - { - // if the param is a node reference - if (NodeRef.class.isAssignableFrom(param)) - { - // mark the transaction as processing a classification check - getAlfrescoTransactionSupport().bindResource(KEY_PROCESSING, Boolean.TRUE); - try - { - // get the value of the parameter - NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position]; - - // if node exists then see if the current user has clearance - result = checkNode(testNodeRef); - } - finally - { - // clear the transaction as processed a classification check - getAlfrescoTransactionSupport().unbindResource(KEY_PROCESSING); - } - } - - position++; - } - } - } - - return result; - } - }, true); - } - - private boolean isUserValid() - { - boolean result = false; - - // check that we have an authenticated user and that they aren't "system" - if (isNotBlank(getAuthenticationUtil().getFullyAuthenticatedUser()) && - !getAuthenticationUtil().isRunAsUserTheSystemUser()) - { - result = true; - } - - return result; - } - - private NodeRef checkNode(NodeRef testNodeRef) throws AccessDeniedException - { - NodeRef result = testNodeRef; - - if (getNodeService().exists(testNodeRef) && - getDictionaryService().isSubClass(getNodeService().getType(testNodeRef), TYPE_CONTENT) && - !getContentClassificationService().hasClearance(testNodeRef)) - { - // FIXME - result = null; - //throw new AccessDeniedException("You do not have clearance!"); - } - - return result; - } - - /** - * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) - */ - @Override - public Object invoke(MethodInvocation invocation) throws Throwable - { - // FIXME - //NodeRef preInvocation = null; - Object postInvocation = null; - - boolean isUserValid = isUserValid(); - - // pre method invocation check - if (isUserValid) - { - // FIXME - //preInvocation = checkClassification(invocation); - //checkClassification(invocation); - } - - // method proceed - postInvocation = invocation.proceed(); - - // post method invocation processing - if (isUserValid && postInvocation != null) - { - Class clazz = postInvocation.getClass(); - BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessorRegistry().getProcessor(clazz); - - if (processor != null) - { - postInvocation = processor.process(postInvocation); - } - else - { - LOG.debug("No post method invocation processor found for '" + clazz + "'."); - } - } - - return postInvocation; - } -} +/* + * 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; + +import static org.alfresco.repo.security.authentication.AuthenticationUtil.getFullyAuthenticatedUser; +import static org.alfresco.repo.security.authentication.AuthenticationUtil.isRunAsUserTheSystemUser; +import static org.alfresco.util.ParameterCheck.mandatory; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PostMethodInvocationProcessor; +import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PreMethodInvocationProcessor; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +/** + * Classification method interceptor + * + * @author Roy Wetherall + * @author Tuna Aksoy + * @since 3.0 + */ +public class ClassificationMethodInterceptor implements MethodInterceptor +{ + /** Pre method invocation processor */ + private PreMethodInvocationProcessor preMethodInvocationProcessor; + + /** Post method invocation processor */ + private PostMethodInvocationProcessor postMethodInvocationProcessor; + + /** + * @return the preMethodInvocationProcessor + */ + protected PreMethodInvocationProcessor getPreMethodInvocationProcessor() + { + return this.preMethodInvocationProcessor; + } + + /** + * @return the postMethodInvocationProcessor + */ + protected PostMethodInvocationProcessor getPostMethodInvocationProcessor() + { + return this.postMethodInvocationProcessor; + } + + /** + * @param postMethodInvocationProcessor the postMethodInvocationProcessor to set + */ + public void setPostMethodInvocationProcessor(PostMethodInvocationProcessor postMethodInvocationProcessor) + { + this.postMethodInvocationProcessor = postMethodInvocationProcessor; + } + + /** + * @param preMethodInvocationProcessor the preMethodInvocationProcessor to set + */ + public void setPreMethodInvocationProcessor(PreMethodInvocationProcessor preMethodInvocationProcessor) + { + this.preMethodInvocationProcessor = preMethodInvocationProcessor; + } + + /** + * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) + */ + @Override + public Object invoke(MethodInvocation invocation) throws Throwable + { + mandatory("invocation", invocation); + + Object result = null; + + boolean canProceed = true; + boolean isUserValid = isUserValid(); + + if (isUserValid) + { + //FIXME!!! + // Pre method invocation processing + //canProceed = getPreMethodInvocationProcessor().process(invocation); + } + + if (canProceed) + { + // Method invocation + result = invocation.proceed(); + + // Post method invocation processing + if (isUserValid && result != null) + { + result = getPostMethodInvocationProcessor().process(result); + } + } + + return result; + } + + /** + * Checks if we have an authenticated user and that they aren't "System" + * + * @return true if we have an authenticated user and that they aren't "System", false otherwise. + */ + private boolean isUserValid() + { + boolean result = false; + + if (isNotBlank(getFullyAuthenticatedUser()) && !isRunAsUserTheSystemUser()) + { + result = true; + } + + return result; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java index 010d2e98cd..5bb5be1062 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java @@ -32,17 +32,17 @@ import org.springframework.beans.factory.support.ManagedList; *

* Bean factory post processor that inspects available beans and adds the classification method interceptor * to all public services. - * + * * @author Roy Wetherall * @since 3.0.a */ public class ClassificationMethodInterceptorPostProcessor implements BeanFactoryPostProcessor { private static final String PROP_INTERCEPTOR_NAMES = "interceptorNames"; - private static final String TYPE_PROXY_FACTORY_BEAN = "ProxyFactoryBean"; + private static final String TYPE_PROXY_FACTORY_BEAN = "ProxyFactoryBean"; private static final String POSTFIX_SERVICE = "Service"; private static final String BEAN_NAME_CLASSIFICATION_METHOD_INTERCEPTOR = "classificationMethodInterceptor"; - + /** * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) */ @@ -56,27 +56,27 @@ public class ClassificationMethodInterceptorPostProcessor implements BeanFactory { // get bean definition BeanDefinition beanDefinition = beanFactory.getBeanDefinition(bean); - + // only modify proxy factory beans that follow the public service naming postfix convention - if (beanDefinition.getBeanClassName() != null && + if (beanDefinition.getBeanClassName() != null && beanDefinition.getBeanClassName().endsWith(TYPE_PROXY_FACTORY_BEAN) && bean.endsWith(POSTFIX_SERVICE)) - { + { // get the property values for the bean definition MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); if (propertyValues.contains(PROP_INTERCEPTOR_NAMES)) { // get the current list of interceptor names - PropertyValue value = propertyValues.getPropertyValue(PROP_INTERCEPTOR_NAMES); + PropertyValue value = propertyValues.getPropertyValue(PROP_INTERCEPTOR_NAMES); ManagedList list = (ManagedList)value.getValue(); if (!list.isEmpty()) { // add reference to classification method interceptor RuntimeBeanNameReference beanReference = new RuntimeBeanNameReference(BEAN_NAME_CLASSIFICATION_METHOD_INTERCEPTOR); list.add(beanReference); - } + } } } - } + } } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java index 022dbed21e..e86eef1983 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java @@ -18,8 +18,6 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import static org.alfresco.util.ParameterCheck.mandatory; - import java.util.Collection; /** @@ -54,23 +52,24 @@ public abstract class AbstractPostMethodInvocationProcessor extends BasePostMeth @Override public T process(T object) { - mandatory("object", object); + T result = object; - T result = null; - - if (isCollection(object)) + if (result != null) { - Collection collection = ((Collection) object); - if (!collection.isEmpty()) + if (isCollection(result)) { - checkObjectClass(collection.iterator().next()); - result = (T) processCollection(collection); + Collection collection = ((Collection) result); + if (!collection.isEmpty()) + { + checkObjectClass(collection.iterator().next()); + result = (T) processCollection(collection); + } + } + else + { + checkObjectClass(result); + result = processSingleElement(result); } - } - else - { - checkObjectClass(object); - result = (T) processSingleElement(object); } return result; 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 9ada7a259e..ba690141f2 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 @@ -23,7 +23,6 @@ import static org.alfresco.model.ContentModel.TYPE_CONTENT; import java.util.Collection; import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; -import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ClassificationPostMethodInvocationException.NotSupportedClassTypeException; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; @@ -37,9 +36,6 @@ import org.alfresco.service.cmr.repository.NodeService; */ public abstract class BasePostMethodInvocationProcessor { - /** Classification method interceptor */ - private ClassificationMethodInterceptor classificationMethodInterceptor; - /** Node service */ private NodeService nodeService; @@ -49,16 +45,8 @@ public abstract class BasePostMethodInvocationProcessor /** Content classification service */ private ContentClassificationService contentClassificationService; - /** Post method invocation processor registry */ - private PostMethodInvocationProcessorRegistry postMethodInvocationProcessorRegistry; - - /** - * @return the classificationMethodInterceptor - */ - protected ClassificationMethodInterceptor getClassificationMethodInterceptor() - { - return this.classificationMethodInterceptor; - } + /** Post method invocation processor */ + private PostMethodInvocationProcessor postMethodInvocationProcessor; /** * @return the nodeService @@ -85,19 +73,11 @@ public abstract class BasePostMethodInvocationProcessor } /** - * @return the postMethodInvocationProcessorRegistry + * @return the postMethodInvocationProcessor */ - protected PostMethodInvocationProcessorRegistry getPostMethodInvocationProcessorRegistry() + protected PostMethodInvocationProcessor getPostMethodInvocationProcessor() { - return this.postMethodInvocationProcessorRegistry; - } - - /** - * @param classificationMethodInterceptor the classificationMethodInterceptor to set - */ - public void setClassificationMethodInterceptor(ClassificationMethodInterceptor classificationMethodInterceptor) - { - this.classificationMethodInterceptor = classificationMethodInterceptor; + return this.postMethodInvocationProcessor; } /** @@ -125,11 +105,11 @@ public abstract class BasePostMethodInvocationProcessor } /** - * @param postMethodInvocationProcessorRegistry the postMethodInvocationProcessorRegistry to set + * @param postMethodInvocationProcessor the postMethodInvocationProcessor to set */ - public void setPostMethodInvocationProcessorRegistry(PostMethodInvocationProcessorRegistry postMethodInvocationProcessorRegistry) + public void setPostMethodInvocationProcessor(PostMethodInvocationProcessor postMethodInvocationProcessor) { - this.postMethodInvocationProcessorRegistry = postMethodInvocationProcessorRegistry; + this.postMethodInvocationProcessor = postMethodInvocationProcessor; } /** @@ -152,7 +132,7 @@ public abstract class BasePostMethodInvocationProcessor */ public void register() { - getPostMethodInvocationProcessorRegistry().register(this); + getPostMethodInvocationProcessor().register(this); } /** 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 7af8983451..89a62e0714 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 @@ -71,7 +71,7 @@ public class ChildAssociationRefPostMethodInvocationProcessor extends AbstractPo @Override public Boolean apply(ChildAssociationRef childAssociationRef) { - return process(childAssociationRef) != null; + return processSingleElement(childAssociationRef) != null; } }); } 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 index 527e144b3e..7c0160f65f 100644 --- 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 @@ -18,8 +18,6 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import static org.alfresco.util.ParameterCheck.mandatory; - import java.util.Collection; import java.util.Iterator; @@ -34,29 +32,29 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) */ - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ "rawtypes" }) @Override public T process(T object) { - mandatory("object", object); + T result = object; - Object result = object; - Collection collection = ((Collection) object); - - if (!collection.isEmpty()) + if (result != null) { - Iterator iterator = collection.iterator(); - if (iterator.hasNext()) + Collection collection = ((Collection) result); + if (!collection.isEmpty()) { - Class clazz = iterator.next().getClass(); - BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessorRegistry().getProcessor(clazz); - if (processor != null) + Iterator iterator = collection.iterator(); + if (iterator.hasNext()) { - result = processor.process(object); + BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(iterator.next()); + if (processor != null) + { + result = processor.process(object); + } } } } - return (T) result; + return result; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java similarity index 59% rename from rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java rename to rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java index d4e6f0e10a..3c1a81ac07 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java @@ -22,6 +22,10 @@ import static org.alfresco.util.ParameterCheck.mandatory; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.log4j.Logger; /** * Registry for post method invocation processors @@ -29,8 +33,11 @@ import java.util.Map; * @author Tuna Aksoy * @since 3.0 */ -public class PostMethodInvocationProcessorRegistry +public class PostMethodInvocationProcessor { + /** Logger */ + private static Logger LOG = Logger.getLogger(PostMethodInvocationProcessor.class); + /** Post method invocation processors */ private Map, BasePostMethodInvocationProcessor> processors = new HashMap, BasePostMethodInvocationProcessor>(); @@ -51,7 +58,7 @@ public class PostMethodInvocationProcessorRegistry * * @return the processors Available processors */ - public Map, BasePostMethodInvocationProcessor> getProcessors() + private Map, BasePostMethodInvocationProcessor> getProcessors() { return this.processors; } @@ -59,24 +66,52 @@ public class PostMethodInvocationProcessorRegistry /** * Gets the processor from the available processors * - * @param clazz The runtime class of the post invocation object + * @param object The post invocation object * @return The suitable processor for the given class */ - public BasePostMethodInvocationProcessor getProcessor(Class clazz) + protected BasePostMethodInvocationProcessor getProcessor(Object object) { - mandatory("clazz", clazz); + mandatory("object", object); BasePostMethodInvocationProcessor result = null; + Class clazz = object.getClass(); - for (Map.Entry, BasePostMethodInvocationProcessor> processor : getProcessors().entrySet()) + Set, BasePostMethodInvocationProcessor>> processorsEntrySet = getProcessors().entrySet(); + for (Map.Entry, BasePostMethodInvocationProcessor> processorEntry : processorsEntrySet) { - if (processor.getKey().isAssignableFrom(clazz)) + if (processorEntry.getKey().isAssignableFrom(clazz)) { - result = processor.getValue(); + result = processorEntry.getValue(); break; } } return result; } + + /** + * Processes the given object + * + * @param object The object to process + * @return The processed object + */ + public T process(T object) + { + T result = object; + + if (result != null) + { + BasePostMethodInvocationProcessor processor = getProcessor(result); + if (processor != null) + { + result = processor.process(result); + } + else + { + LOG.debug("No processor found for '" + result + "'."); + } + } + + return result; + } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java new file mode 100644 index 0000000000..d19bc5b1f8 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java @@ -0,0 +1,173 @@ +/* + * 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 static java.lang.Boolean.TRUE; +import static org.alfresco.model.ContentModel.TYPE_CONTENT; +import static org.alfresco.util.GUID.generate; +import static org.alfresco.util.ParameterCheck.mandatory; + +import java.lang.reflect.Method; + +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.util.AlfrescoTransactionSupport; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.transaction.TransactionService; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * Pre method invocation processor + * + * @author Roy Wetherall + * @author Tuna Aksoy + * @since 3.0 + */ +public class PreMethodInvocationProcessor implements ApplicationContextAware +{ + private static final String KEY_PROCESSING = generate(); + + private ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + this.applicationContext = applicationContext; + } + + protected ContentClassificationService getContentClassificationService() + { + return (ContentClassificationService)applicationContext.getBean("contentClassificationService"); + } + + protected AlfrescoTransactionSupport getAlfrescoTransactionSupport() + { + return (AlfrescoTransactionSupport)applicationContext.getBean("rm.alfrescoTransactionSupport"); + } + + protected RetryingTransactionHelper getRetryingTransactionHelper() + { + return ((TransactionService)applicationContext.getBean("transactionService")).getRetryingTransactionHelper(); + } + + protected ClassificationServiceBootstrap getClassificationServiceBootstrap() + { + return (ClassificationServiceBootstrap)applicationContext.getBean("classificationServiceBootstrap"); + } + + protected NodeService getNodeService() + { + return (NodeService)applicationContext.getBean("dbNodeService"); + } + + protected DictionaryService getDictionaryService() + { + return (DictionaryService)applicationContext.getBean("dictionaryService"); + } + + /** + * Checks if the current user is cleared to see the items + * passed as parameters to the current method invocation. + * + * @param invocation The current method invocation + * @return true if the user is cleared to see the items, false otherwise + */ + public boolean process(final MethodInvocation invocation) + { + mandatory("invocation", invocation); + + // do in transaction + return getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + @SuppressWarnings("rawtypes") + public Boolean execute() throws Throwable + { + Boolean result = true; + + // ensure classification service has been bootstrapped + if (getClassificationServiceBootstrap().isInitialised()) + { + // check that we are not already processing a classification check + Object value = getAlfrescoTransactionSupport().getResource(KEY_PROCESSING); + if (value == null) + { + Method method = invocation.getMethod(); + Class[] params = method.getParameterTypes(); + + int position = 0; + for (Class param : params) + { + // if the param is a node reference + if (NodeRef.class.isAssignableFrom(param)) + { + // mark the transaction as processing a classification check + getAlfrescoTransactionSupport().bindResource(KEY_PROCESSING, TRUE); + try + { + // get the value of the parameter + NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position]; + + // if node exists then see if the current user has clearance + result = isNodeCleared(testNodeRef); + } + finally + { + // clear the transaction as processed a classification check + getAlfrescoTransactionSupport().unbindResource(KEY_PROCESSING); + } + } + + position++; + } + } + } + + return result; + } + }, true); + } + + /** + * Checks if the given node exists, if it is a content and if + * the currently logged in user is cleared to see it. + * + * @param nodeRef Node reference to check + * @return true if the node passes the checks, false otherwise + */ + private boolean isNodeCleared(NodeRef nodeRef) + { + boolean result = true; + + if (getNodeService().exists(nodeRef) && + getDictionaryService().isSubClass(getNodeService().getType(nodeRef), TYPE_CONTENT) && + !getContentClassificationService().hasClearance(nodeRef)) + { + result = false; + } + + return result; + } +} diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java index 3bdf4ef2cd..89735d7472 100644 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java @@ -46,12 +46,6 @@ public class NodeRefPostMethodInvocationProcessorUnitTest extends BaseUnitTest @InjectMocks private NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor; @Mock private ContentClassificationService mockedContentClassificationService; - @Test (expected = IllegalArgumentException.class) - public void testProcessingNull() - { - nodeRefPostMethodInvocationProcessor.process(null); - } - @Test (expected = NotSupportedClassTypeException.class) public void testProccessingAnotherClassType() {