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@106103 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Tuna Aksoy
2015-06-14 21:05:58 +00:00
parent aa746dd474
commit b83bc89275
10 changed files with 398 additions and 48 deletions

View File

@@ -66,6 +66,25 @@
class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AssociationRefPostMethodInvocationProcessor">
</bean>
<bean id="collectionPostMethodInvocationProcessor"
abstract="true"
parent="basePostMethodInvocationProcessor"
class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.CollectionPostMethodInvocationProcessor">
<property name="nodeRefPostMethodInvocationProcessor" ref="nodeRefPostMethodInvocationProcessor" />
<property name="childAssociationRefPostMethodInvocationProcessor" ref="childAssociationRefPostMethodInvocationProcessor" />
<property name="associationRefPostMethodInvocationProcessor" ref="associationRefPostMethodInvocationProcessor" />
</bean>
<bean id="setPostMethodInvocationProcessor"
parent="collectionPostMethodInvocationProcessor"
class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.SetPostMethodInvocationProcessor">
</bean>
<bean id="listPostMethodInvocationProcessor"
parent="collectionPostMethodInvocationProcessor"
class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ListPostMethodInvocationProcessor">
</bean>
<!-- Classification service DAO -->
<bean id="classificationServiceDAO" class="org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceDAO">

View File

@@ -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.

View File

@@ -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<Void>()
return getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<NodeRef>()
{
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<? extends Object> clazz = result.getClass();
BasePostMethodInvocationProcessor processor = processors.get(clazz);
Class<? extends Object> 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<Class<?>, BasePostMethodInvocationProcessor> processors, Class<? extends Object> clazz)
{
BasePostMethodInvocationProcessor result = null;
for (Map.Entry<Class<?>, BasePostMethodInvocationProcessor> processor : processors.entrySet())
{
if (processor.getKey().isAssignableFrom(clazz))
{
result = processor.getValue();
break;
}
}

View File

@@ -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;
}
}

View File

@@ -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 extends Object> 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:
*
* <ul>
* <li>Does the node exist</li>
* <li>Is it a content</li>
* <li>Is the logged in user cleared to see the it.</li>
* </ul>
* 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 <code>null</code> 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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> T process(T object)
{
Object result = object;
Collection collection = ((Collection) object);
if (!collection.isEmpty())
{
Iterator iterator = collection.iterator();
if (iterator.hasNext())
{
Class<? extends Object> 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<NodeRef>()
{
@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<AssociationRef>()
{
@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<ChildAssociationRef>()
{
@Override
public Boolean apply(ChildAssociationRef childAssociationRef)
{
return getChildAssociationRefPostMethodInvocationProcessor().process(childAssociationRef) != null;
}
});
return collection;
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<List> getClassName()
{
return List.class;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object)
*/
@Override
public <T> T process(T object)
{
return super.process(object);
}
}

View File

@@ -47,8 +47,6 @@ public class NodeRefPostMethodInvocationProcessor extends BasePostMethodInvocati
{
mandatory("object", object);
check(((NodeRef) object));
return object;
return filter((NodeRef) object) == null ? null : object;
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<Set> getClassName()
{
return Set.class;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object)
*/
@Override
public <T> T process(T object)
{
return super.process(object);
}
}