Merge release/V2.3 into release/2.4

This commit is contained in:
Ana Bozianu
2016-09-21 11:58:40 +03:00
48 changed files with 5055 additions and 1257 deletions

View File

@@ -60,6 +60,7 @@
org.alfresco.service.cmr.security.PermissionService.hasPermission=ACL_ALLOW org.alfresco.service.cmr.security.PermissionService.hasPermission=ACL_ALLOW
org.alfresco.service.cmr.security.PermissionService.getReaders=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.security.PermissionService.getReaders=ACL_METHOD.ROLE_ADMINISTRATOR
org.alfresco.repo.security.permissions.impl.ExtendedPermissionService.getWriters=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.repo.security.permissions.impl.ExtendedPermissionService.getWriters=ACL_METHOD.ROLE_ADMINISTRATOR
org.alfresco.repo.security.permissions.impl.ExtendedPermissionService.getReadersAndWriters=ACL_METHOD.ROLE_ADMINISTRATOR
org.alfresco.service.cmr.security.PermissionService.deletePermissions=ACL_NODE.0.sys:base.ChangePermissions org.alfresco.service.cmr.security.PermissionService.deletePermissions=ACL_NODE.0.sys:base.ChangePermissions
org.alfresco.service.cmr.security.PermissionService.deletePermission=ACL_NODE.0.sys:base.ChangePermissions org.alfresco.service.cmr.security.PermissionService.deletePermission=ACL_NODE.0.sys:base.ChangePermissions
org.alfresco.service.cmr.security.PermissionService.setPermission=ACL_NODE.0.sys:base.ChangePermissions org.alfresco.service.cmr.security.PermissionService.setPermission=ACL_NODE.0.sys:base.ChangePermissions

View File

@@ -56,3 +56,4 @@ log4j.logger.org.alfresco.module.org_alfresco_module_rm.patch=info
# Job debug # Job debug
# #
#log4j.logger.org.alfresco.module.org_alfresco_module_rm.job=debug #log4j.logger.org.alfresco.module.org_alfresco_module_rm.job=debug
log4j.logger.org.alfresco.repo.web.scripts.roles.DynamicAuthoritiesGet=info

View File

@@ -574,6 +574,9 @@
<property name="nodeService" ref="nodeService"/> <property name="nodeService" ref="nodeService"/>
<property name="filePlanService" ref="filePlanService" /> <property name="filePlanService" ref="filePlanService" />
<property name="filePlanRoleService" ref="filePlanRoleService" /> <property name="filePlanRoleService" ref="filePlanRoleService" />
<property name="authorityService" ref="authorityService"/>
<property name="permissionService" ref="permissionService"/>
<property name="transactionService" ref="transactionService"/>
</bean> </bean>
<bean id="ExtendedSecurityService" class="org.springframework.aop.framework.ProxyFactoryBean"> <bean id="ExtendedSecurityService" class="org.springframework.aop.framework.ProxyFactoryBean">

View File

@@ -28,7 +28,6 @@
<property name="cmObjectType" ref="cm.object" /> <property name="cmObjectType" ref="cm.object" />
<property name="extendedPermissionService" ref="ExtendedPermissionService" /> <property name="extendedPermissionService" ref="ExtendedPermissionService" />
<property name="extendedSecurityService" ref="ExtendedSecurityService" /> <property name="extendedSecurityService" ref="ExtendedSecurityService" />
<property name="ownableService" ref="OwnableService" />
</bean> </bean>
<bean class="org.alfresco.util.BeanExtender"> <bean class="org.alfresco.util.BeanExtender">
<property name="beanName" value="versionService" /> <property name="beanName" value="versionService" />

View File

@@ -587,6 +587,19 @@
</property> </property>
</bean> </bean>
<!-- Remove Dynamic Authorities GET webscript -->
<bean id="webscript.org.alfresco.repository.roles.rm-dynamicauthorities.get"
class="org.alfresco.repo.web.scripts.roles.DynamicAuthoritiesGet"
parent="webscript">
<property name="patchDAO" ref="patchDAO"/>
<property name="nodeDAO" ref="nodeDAO"/>
<property name="qnameDAO" ref="qnameDAO"/>
<property name="nodeService" ref="nodeService"/>
<property name="permissionService" ref="permissionService"/>
<property name="extendedSecurityService" ref="extendedSecurityService"/>
<property name="transactionService" ref="transactionService"/>
</bean>
<!-- REST impl for GET Holds --> <!-- REST impl for GET Holds -->
<bean id="webscript.org.alfresco.rma.holds.get" <bean id="webscript.org.alfresco.rma.holds.get"
class="org.alfresco.module.org_alfresco_module_rm.script.hold.HoldsGet" class="org.alfresco.module.org_alfresco_module_rm.script.hold.HoldsGet"

View File

@@ -0,0 +1,13 @@
<webscript>
<shortname>Removes dynamic authorities</shortname>
<description><![CDATA[
Removes dynamic authorities from in place records created in previous verssions.<br/>
URL parameter batchsize is mandatory, and represents the number of records that are processed in one transaction.<br/>
URL parameter maxProcessedRecords is optional, and represents the maximum number of records that will be processed in one request.<br/>
]]>
</description>
<url>/api/rm/rm-dynamicauthorities?batchsize={batchsize}&amp;maxProcessedRecords={maxProcessedRecords?}</url>
<format default="json">argument</format>
<authentication>admin</authentication>
<transaction allow="readonly">required</transaction>
</webscript>

View File

@@ -0,0 +1,30 @@
<#--
#%L
Alfresco Records Management Module
%%
Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
#L%
-->
{
"responsestatus" : "${responsestatus?json_string}",
"message" : "${message?json_string}"
}

View File

@@ -0,0 +1,148 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.security;
import java.util.Set;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Deprecated extended security service for compatibility.
*
* @author Roy Wetherall
*/
public interface DeprecatedExtendedSecurityService
{
/**
* Gets the set of authorities that are extended readers for the given node.
*
* @param nodeRef node reference
* @return {@link Set}<{@link String}> set of extended readers
*
* @deprecated as of 2.5, use {@link ExtendedSecurityService#getReaders(NodeRef)}
*/
Set<String> getExtendedReaders(NodeRef nodeRef);
/**
* Get the set of authorities that are extended writers for the given node.
*
* @param nodeRef node reference
* @return {@link Set}<{@link String}> set of extended writers
*
* @deprecated as of 2.5, use {@link ExtendedSecurityService#getWriters(NodeRef)}
*/
Set<String> getExtendedWriters(NodeRef nodeRef);
/**
* Add extended security for the specified authorities to a node.
*
* As of, 2.5 this method no longer applies the extended security to parents.
*
* @param nodeRef node reference
* @param readers set of authorities to add extended read permissions
* @param writers set of authorities to add extended write permissions
*
* @deprecated as of 2.5, use {@link ExtendedSecurityService#set(NodeRef, Set, Set)}
*/
@Deprecated
void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers);
/**
* Add extended security for the specified authorities to a node.
* <p>
* If specified, the read and write extended permissions are applied to all parents up to the file plan as
* extended read. This ensures parental read, but not parental write.
*
* @param nodeRef node reference
* @param readers set of authorities to add extended read permissions
* @param writers set of authorities to add extended write permissions
* @param applyToParents true if extended security applied to parents (read only) false otherwise.
*
* @deprecated as of 2.5, because extended security is no longer applied to parents. Note that calling this method will
* only apply the extended security to the node and the applyToParents parameter value will be ignored.
*
* @see ExtendedSecurityService#set(NodeRef, Set, Set)
*/
@Deprecated void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents);
/**
* Remove all extended readers and writers from the given node reference.
*
* @param nodeRef node reference
*
* @deprecated as of 2.5, see {@link ExtendedSecurityService#remove(NodeRef)}
*/
@Deprecated void removeAllExtendedSecurity(NodeRef nodeRef);
/**
* Remove the extended security for the specified authorities from a node.
*
* @param nodeRef node reference
* @param readers set of authorities to remove as extended readers
* @param writers set of authorities to remove as extended writers
*
* @deprecated as of 2.5, because partial removal of readers and writers from node or parents is no longer supported.
* Note that calling this method will now remove all extended security from the node and never applied to parents.
*
* @see {@link ExtendedSecurityService#remove(NodeRef)}
*/
@Deprecated void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers);
/**
* Remove the extended security for the specified authorities from a node.
* <p>
* If specified, extended security will also be removed from the parent hierarchy.(read only). Note that
* extended security is records as a reference count, so security will only be utterly removed from the parent
* hierarchy if all references to the authority are removed.
*
* @param nodeRef node reference
* @param readers set of authorities to remove as extended readers
* @param writers set of authorities to remove as extedned writers
* @param applyToParents true if removal of extended security is applied to parent hierarchy (read only), false
* otherwise
*
* @deprecated as of 2.5, because partial removal of readers and writers from node or parents is no longer supported.
* Note that calling this method will now remove all extended security from the node and never applied to parents.
*
* @see {@link ExtendedSecurityService#remove(NodeRef)}
*/
@Deprecated void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents);
/**
* Remove all extended readers and writers from the given node reference.
*
* @param nodeRef node reference
* @param applyToParents if true then apply removal to parent hierarchy (read only) false otherwise.
*
* @deprecated as of 2.5, because partial removal of readers and writers from node or parents is no longer supported.
* Note that calling this method will now remove all extended security from the node and never applied to parents.
*
* @see {@link ExtendedSecurityService#remove(NodeRef)}
*/
@Deprecated void removeAllExtendedSecurity(NodeRef nodeRef, boolean applyToParents);
}

View File

@@ -41,6 +41,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.1 * @since 2.1
*/ */
@Deprecated
public class ExtendedReaderDynamicAuthority extends ExtendedSecurityBaseDynamicAuthority public class ExtendedReaderDynamicAuthority extends ExtendedSecurityBaseDynamicAuthority
{ {
/** Extended reader role */ /** Extended reader role */

View File

@@ -48,6 +48,7 @@ import org.springframework.context.ApplicationContextAware;
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.1 * @since 2.1
*/ */
@Deprecated
public abstract class ExtendedSecurityBaseDynamicAuthority implements DynamicAuthority, public abstract class ExtendedSecurityBaseDynamicAuthority implements DynamicAuthority,
RecordsManagementModel, RecordsManagementModel,
ApplicationContextAware ApplicationContextAware

View File

@@ -42,6 +42,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.1 * @since 2.1
*/ */
@Deprecated
public class ExtendedWriterDynamicAuthority extends ExtendedSecurityBaseDynamicAuthority public class ExtendedWriterDynamicAuthority extends ExtendedSecurityBaseDynamicAuthority
{ {
/** Extended writer role */ /** Extended writer role */

View File

@@ -35,6 +35,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
* *
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.1 * @since 2.1
* @deprecated as of 2.2, use {@link AuthenticationUtil}.
*/ */
public interface FilePlanAuthenticationService public interface FilePlanAuthenticationService
{ {

View File

@@ -34,6 +34,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.1 * @since 2.1
*/ */
@Deprecated
public class FilePlanAuthenticationServiceImpl implements FilePlanAuthenticationService public class FilePlanAuthenticationServiceImpl implements FilePlanAuthenticationService
{ {
/** Default rm admin user values */ /** Default rm admin user values */

View File

@@ -143,7 +143,7 @@ public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstr
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef) * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
*/ */
@Override @Override
protected synchronized void executeImpl(Action action, final NodeRef actionedUponNodeRef) protected synchronized void executeImpl(final Action action, final NodeRef actionedUponNodeRef)
{ {
String actionName = action.getActionDefinitionName(); String actionName = action.getActionDefinitionName();
if (isOkToProceedWithAction(actionedUponNodeRef, actionName)) if (isOkToProceedWithAction(actionedUponNodeRef, actionName))
@@ -166,7 +166,24 @@ public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstr
if (recordFolder == null) if (recordFolder == null)
{ {
final boolean finaltargetIsUnfiledRecords = targetIsUnfiledRecords; final boolean finaltargetIsUnfiledRecords = targetIsUnfiledRecords;
recordFolder = createOrResolvePath(action, actionedUponNodeRef, finaltargetIsUnfiledRecords); recordFolder = retryingTransactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
NodeRef result = null;
try
{
// get the reference to the record folder based on the relative path
result = createOrResolvePath(action, actionedUponNodeRef, finaltargetIsUnfiledRecords);
}
catch (DuplicateChildNodeNameException ex)
{
throw new ConcurrencyFailureException("Cannot create or resolve path.", ex);
}
return result;
}
}, false, true);
} }
// now we have the reference to the target folder we can do some final checks to see if the action is valid // now we have the reference to the target folder we can do some final checks to see if the action is valid
@@ -179,6 +196,8 @@ public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstr
public Void doWork() public Void doWork()
{ {
try try
{
synchronized (this)
{ {
if (getMode() == CopyMoveLinkFileToActionMode.MOVE) if (getMode() == CopyMoveLinkFileToActionMode.MOVE)
{ {
@@ -193,16 +212,15 @@ public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstr
getRecordService().link(actionedUponNodeRef, finalRecordFolder); getRecordService().link(actionedUponNodeRef, finalRecordFolder);
} }
} }
}
catch (FileNotFoundException fileNotFound) catch (FileNotFoundException fileNotFound)
{ {
throw new AlfrescoRuntimeException( throw new AlfrescoRuntimeException("Unable to execute file to action, because the " + (mode == CopyMoveLinkFileToActionMode.MOVE ? "move" : "copy") + " operation failed.", fileNotFound);
"Unable to execute file to action, because the " + (mode == CopyMoveLinkFileToActionMode.MOVE ? "move" : "copy") + " operation failed.",
fileNotFound
);
} }
return null; return null;
} }
}); });
} }
} }

View File

@@ -42,8 +42,6 @@ import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService; import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.domain.node.NodeDAO;
@@ -360,8 +358,6 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
// set inheritance to false // set inheritance to false
getPermissionService().setInheritParentPermissions(container, false); getPermissionService().setInheritParentPermissions(container, false);
getPermissionService().setPermission(container, allRoles, RMPermissionModel.READ_RECORDS, true); getPermissionService().setPermission(container, allRoles, RMPermissionModel.READ_RECORDS, true);
getPermissionService().setPermission(container, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
getPermissionService().setPermission(container, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
// prevent inheritance of rules // prevent inheritance of rules
nodeService.addAspect(container, RuleModel.ASPECT_IGNORE_INHERITED_RULES, null); nodeService.addAspect(container, RuleModel.ASPECT_IGNORE_INHERITED_RULES, null);

View File

@@ -251,9 +251,10 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel
QName PROP_LOADED_DATA_SET_IDS = QName.createQName(RM_URI, "loadedDataSetIds"); QName PROP_LOADED_DATA_SET_IDS = QName.createQName(RM_URI, "loadedDataSetIds");
// Extended security aspect // Extended security aspect
QName ASPECT_EXTENDED_SECURITY = QName.createQName(RM_URI, "extendedSecurity"); // @deprecated as of 2.5, because of performance issues
QName PROP_READERS = QName.createQName(RM_URI, "readers"); @Deprecated QName ASPECT_EXTENDED_SECURITY = QName.createQName(RM_URI, "extendedSecurity");
QName PROP_WRITERS = QName.createQName(RM_URI, "writers"); @Deprecated QName PROP_READERS = QName.createQName(RM_URI, "readers");
@Deprecated QName PROP_WRITERS = QName.createQName(RM_URI, "writers");
// Originating details of a record // Originating details of a record
QName ASPECT_RECORD_ORIGINATING_DETAILS = QName.createQName(RM_URI, "recordOriginatingDetails"); QName ASPECT_RECORD_ORIGINATING_DETAILS = QName.createQName(RM_URI, "recordOriginatingDetails");

View File

@@ -39,6 +39,7 @@ import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService; import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.repo.copy.CopyBehaviourCallback; import org.alfresco.repo.copy.CopyBehaviourCallback;
import org.alfresco.repo.copy.CopyDetails; import org.alfresco.repo.copy.CopyDetails;
import org.alfresco.repo.copy.CopyServicePolicies;
import org.alfresco.repo.copy.DefaultCopyBehaviourCallback; import org.alfresco.repo.copy.DefaultCopyBehaviourCallback;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
@@ -65,7 +66,8 @@ public class RecordAspect extends AbstractDisposableItem
implements NodeServicePolicies.OnCreateChildAssociationPolicy, implements NodeServicePolicies.OnCreateChildAssociationPolicy,
RecordsManagementPolicies.OnCreateReference, RecordsManagementPolicies.OnCreateReference,
RecordsManagementPolicies.OnRemoveReference, RecordsManagementPolicies.OnRemoveReference,
NodeServicePolicies.OnMoveNodePolicy NodeServicePolicies.OnMoveNodePolicy,
CopyServicePolicies.OnCopyCompletePolicy
{ {
/** Well-known location of the scripts folder. */ /** Well-known location of the scripts folder. */
// TODO make configurable // TODO make configurable
@@ -132,11 +134,11 @@ public class RecordAspect extends AbstractDisposableItem
// manage any extended readers // manage any extended readers
NodeRef parent = childAssocRef.getParentRef(); NodeRef parent = childAssocRef.getParentRef();
Set<String> readers = extendedSecurityService.getExtendedReaders(parent); Set<String> readers = extendedSecurityService.getReaders(parent);
Set<String> writers = extendedSecurityService.getExtendedWriters(parent); Set<String> writers = extendedSecurityService.getWriters(parent);
if (readers != null && readers.size() != 0) if (readers != null && readers.size() != 0)
{ {
extendedSecurityService.addExtendedSecurity(thumbnail, readers, writers, false); extendedSecurityService.set(thumbnail, readers, writers);
} }
} }
@@ -305,4 +307,33 @@ public class RecordAspect extends AbstractDisposableItem
scriptService.executeScript(scriptNodeRef, null, objectModel); scriptService.executeScript(scriptNodeRef, null, objectModel);
} }
} }
/**
* On copy complete behaviour for record aspect.
*
* @param classRef
* @param sourceNodeRef
* @param targetNodeRef
* @param copyToNewNode
* @param copyMap
*/
@Override
@Behaviour
(
kind = BehaviourKind.CLASS
)
public void onCopyComplete(QName classRef,
NodeRef sourceNodeRef,
NodeRef targetNodeRef,
boolean copyToNewNode,
Map<NodeRef, NodeRef> copyMap)
{
// given the node exists and is a record
if (nodeService.exists(targetNodeRef) &&
nodeService.hasAspect(targetNodeRef, ASPECT_RECORD))
{
// then remove any extended security from the newly copied record
extendedSecurityService.remove(targetNodeRef);
}
}
} }

View File

@@ -34,13 +34,10 @@ import java.util.Set;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.Capability; import org.alfresco.module.org_alfresco_module_rm.capability.Capability;
import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.dod5015.DOD5015Model; import org.alfresco.module.org_alfresco_module_rm.dod5015.DOD5015Model;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService; import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService; import org.alfresco.module.org_alfresco_module_rm.security.FilePlanPermissionService;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -164,10 +161,6 @@ public class RMv21InPlacePatch extends RMv21PatchComponent
ruleService.disableRules(); ruleService.disableRules();
try try
{ {
// set permissions
filePlanPermissionService.setPermission(filePlan, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS);
filePlanPermissionService.setPermission(filePlan, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING);
// create fileplan containers // create fileplan containers
filePlanService.createHoldContainer(filePlan); filePlanService.createHoldContainer(filePlan);
filePlanService.createTransferContainer(filePlan); filePlanService.createTransferContainer(filePlan);

View File

@@ -30,7 +30,6 @@ package org.alfresco.module.org_alfresco_module_rm.record;
import static org.alfresco.model.ContentModel.ASPECT_PENDING_DELETE; import static org.alfresco.model.ContentModel.ASPECT_PENDING_DELETE;
import java.util.List; import java.util.List;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
@@ -104,6 +103,9 @@ public class InplaceRecordServiceImpl extends ServiceBaseImpl implements Inplace
{ {
// remove the child association // remove the child association
NodeRef originatingLocation = (NodeRef) nodeService.getProperty(nodeRef, PROP_RECORD_ORIGINATING_LOCATION); NodeRef originatingLocation = (NodeRef) nodeService.getProperty(nodeRef, PROP_RECORD_ORIGINATING_LOCATION);
if (originatingLocation != null)
{
List<ChildAssociationRef> parentAssocs = nodeService.getParentAssocs(nodeRef); List<ChildAssociationRef> parentAssocs = nodeService.getParentAssocs(nodeRef);
for (ChildAssociationRef childAssociationRef : parentAssocs) for (ChildAssociationRef childAssociationRef : parentAssocs)
{ {
@@ -118,7 +120,8 @@ public class InplaceRecordServiceImpl extends ServiceBaseImpl implements Inplace
// remove the extended security from the node // remove the extended security from the node
// this prevents the users from continuing to see the record in searchs and other linked locations // this prevents the users from continuing to see the record in searchs and other linked locations
extendedSecurityService.removeAllExtendedSecurity(nodeRef); extendedSecurityService.remove(nodeRef);
}
return null; return null;
} }
@@ -173,18 +176,11 @@ public class InplaceRecordServiceImpl extends ServiceBaseImpl implements Inplace
{ {
try try
{ {
// Get the extended readers/writers
Set<String> extendedReaders = extendedSecurityService.getExtendedReaders(nodeRef);
Set<String> extendedWriters = extendedSecurityService.getExtendedWriters(nodeRef);
// Move the record // Move the record
fileFolderService.moveFrom(nodeRef, source, targetNodeRef, null); fileFolderService.moveFrom(nodeRef, source, targetNodeRef, null);
// Update the originating location property // Update the originating location property
nodeService.setProperty(nodeRef, PROP_RECORD_ORIGINATING_LOCATION, targetNodeRef); nodeService.setProperty(nodeRef, PROP_RECORD_ORIGINATING_LOCATION, targetNodeRef);
// Set the extended readers/writers
extendedSecurityService.addExtendedSecurity(nodeRef, extendedReaders, extendedWriters);
} }
catch (FileExistsException | FileNotFoundException ex) catch (FileExistsException | FileNotFoundException ex)
{ {

View File

@@ -107,6 +107,7 @@ import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.EqualsHelper; import org.alfresco.util.EqualsHelper;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyMap; import org.alfresco.util.PropertyMap;
import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.ArrayUtils;
@@ -253,10 +254,6 @@ public class RecordServiceImpl extends BaseBehaviourBean
this, this,
"onCreateChildAssociation", "onCreateChildAssociation",
NotificationFrequency.FIRST_EVENT); NotificationFrequency.FIRST_EVENT);
private JavaBehaviour onDeleteDeclaredRecordLink = new JavaBehaviour(
this,
"onDeleteDeclaredRecordLink",
NotificationFrequency.FIRST_EVENT);
/** /**
* @param identifierService identifier service * @param identifierService identifier service
@@ -417,11 +414,6 @@ public class RecordServiceImpl extends BaseBehaviourBean
TYPE_RECORD_FOLDER, TYPE_RECORD_FOLDER,
ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS,
onCreateChildAssociation); onCreateChildAssociation);
policyComponent.bindAssociationBehaviour(
NodeServicePolicies.BeforeDeleteChildAssociationPolicy.QNAME,
ContentModel.TYPE_FOLDER,
ContentModel.ASSOC_CONTAINS,
onDeleteDeclaredRecordLink);
} }
/** /**
@@ -592,27 +584,6 @@ public class RecordServiceImpl extends BaseBehaviourBean
}, AuthenticationUtil.getSystemUserName()); }, AuthenticationUtil.getSystemUserName());
} }
/**
* Looking specifically at linked content that was declared a record from a non-rm site.
* When the site or the folder that the link was declared in is deleted we need to remove
* the extended security property accounts in the tree
*
* @param childAssocRef
*/
public void onDeleteDeclaredRecordLink(ChildAssociationRef childAssocRef)
{
// Is the deleted child association not a primary association?
// Does the deleted child association have the rma:recordOriginatingDetails aspect?
// Is the parent of the deleted child association a folder (cm:folder)?
if (!childAssocRef.isPrimary() &&
nodeService.hasAspect(childAssocRef.getChildRef(), ASPECT_RECORD_ORIGINATING_DETAILS) &&
nodeService.getType(childAssocRef.getParentRef()).equals(ContentModel.TYPE_FOLDER))
{
// ..then remove the extended readers and writers up the tree for this remaining node
extendedSecurityService.removeExtendedSecurity(childAssocRef.getChildRef(), extendedSecurityService.getExtendedReaders(childAssocRef.getChildRef()), extendedSecurityService.getExtendedWriters(childAssocRef.getChildRef()), true);
}
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#disablePropertyEditableCheck() * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#disablePropertyEditableCheck()
*/ */
@@ -914,12 +885,10 @@ public class RecordServiceImpl extends BaseBehaviourBean
throw new AlfrescoRuntimeException("Unable to create record, because new record container could not be found."); throw new AlfrescoRuntimeException("Unable to create record, because new record container could not be found.");
} }
// get the documents readers // get the documents readers and writers
Long aclId = nodeService.getNodeAclId(nodeRef); Pair<Set<String>, Set<String>> readersAndWriters = extendedPermissionService.getReadersAndWriters(nodeRef);
Set<String> readers = extendedPermissionService.getReaders(aclId);
Set<String> writers = extendedPermissionService.getWriters(aclId);
// add the current owner to the list of extended writers // get the current owner
String owner = ownableService.getOwner(nodeRef); String owner = ownableService.getOwner(nodeRef);
// get the documents primary parent assoc // get the documents primary parent assoc
@@ -971,13 +940,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
nodeService.addChild(parentAssoc.getParentRef(), nodeRef, parentAssoc.getTypeQName(), parentAssoc.getQName()); nodeService.addChild(parentAssoc.getParentRef(), nodeRef, parentAssoc.getTypeQName(), parentAssoc.getQName());
// set the extended security // set the extended security
Set<String> combinedWriters = new HashSet<String>(writers); extendedSecurityService.set(nodeRef, readersAndWriters);
if (owner != null && !owner.isEmpty() && !owner.equals(OwnableService.NO_OWNER))
{
combinedWriters.add(owner);
}
combinedWriters.add(AuthenticationUtil.getFullyAuthenticatedUser());
extendedSecurityService.addExtendedSecurity(nodeRef, readers, combinedWriters);
} }
finally finally
{ {
@@ -1009,24 +972,8 @@ public class RecordServiceImpl extends BaseBehaviourBean
// get the unfiled record folder // get the unfiled record folder
final NodeRef unfiledRecordFolder = filePlanService.getUnfiledContainer(filePlan); final NodeRef unfiledRecordFolder = filePlanService.getUnfiledContainer(filePlan);
// get the documents readers // get the documents readers and writers
Long aclId = nodeService.getNodeAclId(nodeRef); Pair<Set<String>, Set<String>> readersAndWriters = extendedPermissionService.getReadersAndWriters(nodeRef);
Set<String> readers = extendedPermissionService.getReaders(aclId);
Set<String> writers = extendedPermissionService.getWriters(aclId);
// add the current owner to the list of extended writers
Set<String> modifiedWrtiers = new HashSet<String>(writers);
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_OWNABLE))
{
String owner = ownableService.getOwner(nodeRef);
if (owner != null && !owner.isEmpty() && !owner.equals(OwnableService.NO_OWNER))
{
modifiedWrtiers.add(owner);
}
}
// add the current user as extended writer
modifiedWrtiers.add(authenticationUtil.getFullyAuthenticatedUser());
// copy version state and create record // copy version state and create record
NodeRef record = null; NodeRef record = null;
@@ -1095,7 +1042,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
} }
// set extended security on record // set extended security on record
extendedSecurityService.addExtendedSecurity(record, readers, writers); extendedSecurityService.set(record, readersAndWriters);
return record; return record;
} }

View File

@@ -45,8 +45,6 @@ import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authority.RMAuthority; import org.alfresco.repo.security.authority.RMAuthority;
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
@@ -195,8 +193,6 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService,
// Set the permissions // Set the permissions
permissionService.setInheritParentPermissions(filePlan, false); permissionService.setInheritParentPermissions(filePlan, false);
permissionService.setPermission(filePlan, allRoles, RMPermissionModel.READ_RECORDS, true); permissionService.setPermission(filePlan, allRoles, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(filePlan, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(filePlan, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
// Create the transfer and hold containers // Create the transfer and hold containers
systemContainers.add(filePlanService.createHoldContainer(filePlan)); systemContainers.add(filePlanService.createHoldContainer(filePlan));

View File

@@ -29,7 +29,9 @@ package org.alfresco.module.org_alfresco_module_rm.security;
import java.util.Set; import java.util.Set;
import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.Pair;
/** /**
* Extended security service. * Extended security service.
@@ -37,13 +39,17 @@ import org.alfresco.service.cmr.repository.NodeRef;
* @author Roy Wetherall * @author Roy Wetherall
* @since 2.1 * @since 2.1
*/ */
public interface ExtendedSecurityService @AlfrescoPublicApi
public interface ExtendedSecurityService extends DeprecatedExtendedSecurityService
{ {
/** IPR group prefix */
static final String IPR_GROUP_PREFIX = "IPR";
/** /**
* Indicates whether a node has extended security. * Indicates whether a node has extended security.
* *
* @param nodeRef node reference * @param nodeRef node reference
* @return boolean true if the node has extedned security, false otherwise * @return boolean true if the node has extended security, false otherwise
*/ */
boolean hasExtendedSecurity(NodeRef nodeRef); boolean hasExtendedSecurity(NodeRef nodeRef);
@@ -53,7 +59,7 @@ public interface ExtendedSecurityService
* @param nodeRef node reference * @param nodeRef node reference
* @return {@link Set}<{@link String}> set of extended readers * @return {@link Set}<{@link String}> set of extended readers
*/ */
Set<String> getExtendedReaders(NodeRef nodeRef); Set<String> getReaders(NodeRef nodeRef);
/** /**
* Get the set of authorities that are extended writers for the given node. * Get the set of authorities that are extended writers for the given node.
@@ -61,66 +67,39 @@ public interface ExtendedSecurityService
* @param nodeRef node reference * @param nodeRef node reference
* @return {@link Set}<{@link String}> set of extended writers * @return {@link Set}<{@link String}> set of extended writers
*/ */
Set<String> getExtendedWriters(NodeRef nodeRef); Set<String> getWriters(NodeRef nodeRef);
/** /**
* Add extended security for the specified authorities to a node. * Helper to allow caller to provide authority sets as a pair where the
* first is the readers and the second is the writers.
*
* @see #set(NodeRef, Set, Set)
* *
* @param nodeRef node reference * @param nodeRef node reference
* @param readers set of authorities to add extended read permissions * @param readersAndWriters pair where first is the set of readers and the
* @param writers set of authorities to add extended write permissions * second is the set of writers
*/ */
void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers); void set(NodeRef nodeRef, Pair<Set<String>, Set<String>> readersAndWriters);
/** /**
* Add extended security for the specified authorities to a node. * Set extended security for a node, where the readers will be granted ReadRecord
* permission and ViewRecord capability to the node and where the writers will be
* granted Filling permission and Filling capability to the node.
* <p> * <p>
* If specified, the read and write extended permissions are applied to all parents up to the file plan as * Note it is vaild to provide 'null' values for readers and/or writers.
* extended read. This ensures parental read, but not parental write.
* *
* @param nodeRef node reference * @param nodeRef node reference
* @param readers set of authorities to add extended read permissions * @param readers set of readers
* @param writers set of authorities to add extended write permissions * @param writers set of writers
* @param applyToParents true if extended security applied to parents (read only) false otherwise. *
* @since 2.5
*/ */
void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents); void set(NodeRef nodeRef, Set<String> readers, Set<String> writers);
/** /**
* Remove the extended security for the specified authorities from a node. * Removes all extended security from a node.
*
* @param nodeRef node reference
* @param readers set of authorities to remove as extended readers
* @param writers set of authorities to remove as extended writers
*/
void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers);
/**
* Remove the extended security for the specified authorities from a node.
* <p>
* If specified, extended security will also be removed from the parent hierarchy.(read only). Note that
* extended security is records as a reference count, so security will only be utterly removed from the parent
* hierarchy if all references to the authority are removed.
*
* @param nodeRef node reference
* @param readers set of authorities to remove as extended readers
* @param writers set of authorities to remove as extedned writers
* @param applyToParents true if removal of extended security is applied to parent hierarchy (read only), false
* otherwise
*/
void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents);
/**
* Remove all extended readers and writers from the given node reference.
* *
* @param nodeRef node reference * @param nodeRef node reference
*/ */
void removeAllExtendedSecurity(NodeRef nodeRef); void remove(NodeRef nodeRef);
/**
* Remove all extended readers and writers from the given node reference.
*
* @param nodeRef node reference
* @param applyToParents if true then apply removal to parent hierarchy (read only) false otherwise.
*/
void removeAllExtendedSecurity(NodeRef nodeRef, boolean applyToParents);
} }

View File

@@ -27,23 +27,37 @@
package org.alfresco.module.org_alfresco_module_rm.security; package org.alfresco.module.org_alfresco_module_rm.security;
import java.io.Serializable;
import java.util.HashMap; import static org.alfresco.service.cmr.security.PermissionService.GROUP_PREFIX;
import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.model.RenditionModel; import org.alfresco.model.RenditionModel;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService; import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.security.authority.RMAuthority;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessPermission;
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.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.extensions.webscripts.ui.common.StringUtils;
/** /**
* Extended security service implementation. * Extended security service implementation.
@@ -53,14 +67,32 @@ import org.alfresco.util.ParameterCheck;
*/ */
public class ExtendedSecurityServiceImpl extends ServiceBaseImpl public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
implements ExtendedSecurityService, implements ExtendedSecurityService,
RecordsManagementModel RecordsManagementModel,
ApplicationListener<ContextRefreshedEvent>
{ {
/** ipr group names */
static final String ROOT_IPR_GROUP = "INPLACE_RECORD_MANAGEMENT";
static final String READER_GROUP_PREFIX = ExtendedSecurityService.IPR_GROUP_PREFIX + "R";
static final String WRITER_GROUP_PREFIX = ExtendedSecurityService.IPR_GROUP_PREFIX + "W";
/** max page size for authority query */
private static final int MAX_ITEMS = 50;
/** File plan service */ /** File plan service */
private FilePlanService filePlanService; private FilePlanService filePlanService;
/** File plan role service */ /** File plan role service */
private FilePlanRoleService filePlanRoleService; private FilePlanRoleService filePlanRoleService;
/** authority service */
private AuthorityService authorityService;
/** permission service */
private PermissionService permissionService;
/** transaction service */
private TransactionService transactionService;
/** /**
* @param filePlanService file plan service * @param filePlanService file plan service
*/ */
@@ -77,116 +109,150 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
this.filePlanRoleService = filePlanRoleService; this.filePlanRoleService = filePlanRoleService;
} }
/**
* @param authorityService authority service
*/
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
/**
* @param permissionService permission service
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* @param transactionService transaction service
*/
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
/**
* Application context refresh event handler
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent)
{
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
{
// if the root group doesn't exist then create it
if (!authorityService.authorityExists(getRootIRPGroup()))
{
authorityService.createAuthority(AuthorityType.GROUP, ROOT_IPR_GROUP, ROOT_IPR_GROUP, Collections.singleton(RMAuthority.ZONE_APP_RM));
}
return null;
}
});
}
/**
* Get root IPR group name
*/
private String getRootIRPGroup()
{
return GROUP_PREFIX + ROOT_IPR_GROUP;
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#hasExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef) * @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#hasExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef)
*/ */
@Override
public boolean hasExtendedSecurity(NodeRef nodeRef) public boolean hasExtendedSecurity(NodeRef nodeRef)
{ {
return nodeService.hasAspect(nodeRef, ASPECT_EXTENDED_SECURITY); return (getIPRGroups(nodeRef) != null);
} }
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#getExtendedReaders(org.alfresco.service.cmr.repository.NodeRef) * @see org.alfresco.module.org_alfresco_module_rm.security.RecordsManagementSecurityService#getReaders(org.alfresco.service.cmr.repository.NodeRef)
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public Set<String> getExtendedReaders(NodeRef nodeRef) public Set<String> getReaders(NodeRef nodeRef)
{
Set<String> result = null;
Map<String, Integer> readerMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_READERS);
if (readerMap != null)
{
result = readerMap.keySet();
}
return result;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#getExtendedWriters(org.alfresco.service.cmr.repository.NodeRef)
*/
@SuppressWarnings("unchecked")
@Override
public Set<String> getExtendedWriters(NodeRef nodeRef)
{
Set<String> result = null;
Map<String, Integer> map = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_WRITERS);
if (map != null)
{
result = map.keySet();
}
return result;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#addExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set)
*/
@Override
public void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers)
{
addExtendedSecurity(nodeRef, readers, writers, true);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#addExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set, boolean)
*/
@Override
public void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents)
{ {
ParameterCheck.mandatory("nodeRef", nodeRef); ParameterCheck.mandatory("nodeRef", nodeRef);
ParameterCheck.mandatory("applyToParents", applyToParents);
if (nodeRef != null) Set<String> result = Collections.EMPTY_SET;
Pair<String, String> iprGroups = getIPRGroups(nodeRef);
if (iprGroups != null)
{ {
addExtendedSecurityImpl(nodeRef, readers, writers, applyToParents); result = getAuthorities(iprGroups.getFirst());
// add to the extended security roles
addExtendedSecurityRoles(nodeRef, readers, writers);
} }
return result;
} }
/** /**
* Add extended security implementation method * @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#getWriters(org.alfresco.service.cmr.repository.NodeRef)
*/
@SuppressWarnings("unchecked")
@Override
public Set<String> getWriters(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
Set<String> result = Collections.EMPTY_SET;
Pair<String, String> iprGroups = getIPRGroups(nodeRef);
if (iprGroups != null)
{
result = getAuthorities(iprGroups.getSecond());
}
return result;
}
/**
* Helper to get authorities for a given group
* *
* @param nodeRef * @param group group name
* @param readers * @return Set<String> immediate authorities
* @param writers
* @param applyToParents
*/ */
@SuppressWarnings("unchecked") private Set<String> getAuthorities(String group)
private void addExtendedSecurityImpl(final NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents) {
Set<String> result = new HashSet<String>();
result.addAll(authorityService.getContainedAuthorities(null, group, true));
return result;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#set(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.util.Pair)
*/
@Override
public void set(NodeRef nodeRef, Pair<Set<String>, Set<String>> readersAndWriters)
{ {
ParameterCheck.mandatory("nodeRef", nodeRef); ParameterCheck.mandatory("nodeRef", nodeRef);
ParameterCheck.mandatory("applyToParents", applyToParents); set(nodeRef, readersAndWriters.getFirst(), readersAndWriters.getSecond());
// get the properties
final Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
// update the readers map
if (readers != null && readers.size() != 0)
{
// get reader map
Map<String, Integer> readersMap = (Map<String, Integer>)properties.get(PROP_READERS);
// set the readers property (this will in turn apply the aspect if required)
properties.put(PROP_READERS, (Serializable)addToMap(readersMap, readers));
} }
// update the writers map /**
if (writers != null && writers.size() != 0) * @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#set(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set)
*/
@Override
public void set(NodeRef nodeRef, Set<String> readers, Set<String> writers)
{ {
// get writer map ParameterCheck.mandatory("nodeRef", nodeRef);
Map<String, Integer> writersMap = (Map<String, Integer>)properties.get(PROP_WRITERS);
// set the writers property (this will in turn apply the aspect if required) // remove existing extended security, assuming there is any
properties.put(PROP_WRITERS, (Serializable)addToMap(writersMap, writers)); remove(nodeRef);
}
// set properties // find groups
nodeService.setProperties(nodeRef, properties); Pair<String, String> iprGroups = createOrFindIPRGroups(readers, writers);
// assign groups to correct fileplan roles
NodeRef filePlan = filePlanService.getFilePlan(nodeRef);
filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_READERS, iprGroups.getFirst());
filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_WRITERS, iprGroups.getSecond());
// assign groups to node
assignIPRGroupsToNode(iprGroups, nodeRef);
// apply the readers to any renditions of the content // apply the readers to any renditions of the content
if (isRecord(nodeRef)) if (isRecord(nodeRef))
@@ -195,100 +261,299 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
for (ChildAssociationRef assoc : assocs) for (ChildAssociationRef assoc : assocs)
{ {
NodeRef child = assoc.getChildRef(); NodeRef child = assoc.getChildRef();
addExtendedSecurityImpl(child, readers, writers, false); assignIPRGroupsToNode(iprGroups, child);
} }
} }
} }
/** /**
* Get the IPR groups associated with a given node reference.
* <p>
* Return null if none found.
* *
* @param nodeRef * @param nodeRef node reference
* @param readers * @return Pair<String, String> where first is the read group and second if the write group, null if none found
* @param writers
*/ */
private void addExtendedSecurityRoles(NodeRef nodeRef, Set<String> readers, Set<String> writers) private Pair<String, String> getIPRGroups(NodeRef nodeRef)
{ {
NodeRef filePlan = filePlanService.getFilePlan(nodeRef); Pair<String, String> result = null;
String iprReaderGroup = null;
String iprWriterGroup = null;
addExtendedSecurityRolesImpl(filePlan, readers, FilePlanRoleService.ROLE_EXTENDED_READERS); // get all the set permissions
addExtendedSecurityRolesImpl(filePlan, writers, FilePlanRoleService.ROLE_EXTENDED_WRITERS); Set<AccessPermission> permissions = permissionService.getAllSetPermissions(nodeRef);
for (AccessPermission permission : permissions)
{
// look for the presence of the reader group
if (permission.getAuthority().startsWith(GROUP_PREFIX + READER_GROUP_PREFIX))
{
iprReaderGroup = permission.getAuthority();
}
// look for the presence of the writer group
else if (permission.getAuthority().startsWith(GROUP_PREFIX + WRITER_GROUP_PREFIX))
{
iprWriterGroup = permission.getAuthority();
}
}
// assuming the are both present then return
if (iprReaderGroup != null && iprWriterGroup != null)
{
result = new Pair<String, String>(iprReaderGroup, iprWriterGroup);
}
return result;
} }
/** /**
* Add extended security roles implementation * Given a set of readers and writers find or create the appropriate IPR groups.
* <p>
* The IPR groups are named with hashes of the authority lists in order to reduce
* the set of groups that require exact match. A further index is used to handle
* a situation where there is a hash clash, but a difference in the authority lists.
* <p>
* When no match is found the groups are created. Once created
* *
* @param filePlan file plan * @param filePlan file plan
* @param authorities authorities * @param readers authorities with read
* @param roleName role name * @param writers authorities with write
* @return Pair<String, String> where first is the full name of the read group and
* second is the full name of the write group
*/ */
private void addExtendedSecurityRolesImpl(NodeRef filePlan, Set<String> authorities, String roleName) private Pair<String, String> createOrFindIPRGroups(Set<String> readers, Set<String> writers)
{ {
if (authorities != null) return new Pair<String, String>(
{ createOrFindIPRGroup(READER_GROUP_PREFIX, readers),
for (String authority : authorities) createOrFindIPRGroup(WRITER_GROUP_PREFIX, writers));
{
if ((!authority.equals(PermissionService.ALL_AUTHORITIES) && !authority.equals(PermissionService.OWNER_AUTHORITY)))
{
// add the authority to the role
filePlanRoleService.assignRoleToAuthority(filePlan, roleName, authority);
}
}
}
} }
/** /**
* Create or find an IPR group based on the provided prefix and authorities.
* *
* @param map * @param groupPrefix group prefix
* @param keys * @param authorities authorities
* @return * @return String full group name
*/ */
private Map<String, Integer> addToMap(Map<String, Integer> map, Set<String> keys) private String createOrFindIPRGroup(String groupPrefix, Set<String> authorities)
{ {
if (map == null) String group = null;
{
// create map
map = new HashMap<String, Integer>(7);
}
for (String key : keys) // find group or determine what the next index is if no group exists or there is a clash
Pair<String, Integer> groupResult = findIPRGroup(groupPrefix, authorities);
if (groupResult.getFirst() == null)
{ {
if (!key.equals(PermissionService.ALL_AUTHORITIES)) group = createIPRGroup(groupPrefix, authorities, groupResult.getSecond());
{
if (map.containsKey(key))
{
// increment reference count
Integer count = map.get(key);
map.put(key, Integer.valueOf(count.intValue()+1));
} }
else else
{ {
// add key with initial count group = groupResult.getFirst();
map.put(key, Integer.valueOf(1));
}
}
} }
return map; return group;
} }
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#removeExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set) * Given a group name prefix and the authorities, finds the exact match existing group.
* <p>
* If the group does not exist then the group returned is null and the index shows the next available
* group index for creation.
*
* @param groupPrefix group name prefix
* @param authorities authorities
* @return Pair<String, Integer> where first is the name of the found group, null if none found and second
* if the next available create index
*/ */
@Override private Pair<String, Integer> findIPRGroup(String groupPrefix, Set<String> authorities)
public void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers)
{ {
removeExtendedSecurity(nodeRef, readers, writers, true); String iprGroup = null;
int nextGroupIndex = 0;
boolean hasMoreItems = true;
int pageCount = 0;
// determine the short name prefix
String groupShortNamePrefix = getIPRGroupPrefixShortName(groupPrefix, authorities);
// iterate over the authorities to find a match
while (hasMoreItems == true)
{
// get matching authorities
PagingResults<String> results = authorityService.getAuthorities(AuthorityType.GROUP,
RMAuthority.ZONE_APP_RM,
groupShortNamePrefix,
false,
false,
new PagingRequest(MAX_ITEMS*pageCount, MAX_ITEMS));
// record the total count
nextGroupIndex = nextGroupIndex + results.getPage().size();
// see if any of the matching groups exactly match
for (String group : results.getPage())
{
// if exists and matches we have found our group
if (isIPRGroupTrueMatch(group, authorities))
{
iprGroup = group;
break;
}
}
// determine if there are any more pages to inspect
hasMoreItems = results.hasMoreItems();
pageCount ++;
}
return new Pair<String, Integer>(iprGroup, nextGroupIndex);
} }
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#removeExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set, boolean) * Determines whether a group exactly matches a list of authorities.
*
* @param authorities list of authorities
* @param group group
* @return
*/
private boolean isIPRGroupTrueMatch(String group, Set<String> authorities)
{
Set<String> contained = authorityService.getContainedAuthorities(null, group, true);
return contained.equals(authorities);
}
/**
* Get IPR group prefix short name.
* <p>
* 'package' scope to help testing.
*
* @param prefix prefix
* @param authorities authorities
* @return String group prefix short name
*/
/*package*/ String getIPRGroupPrefixShortName(String prefix, Set<String> authorities)
{
StringBuilder builder = new StringBuilder(128)
.append(prefix)
.append(getAuthoritySetHashCode(authorities));
return builder.toString();
}
/**
* Get IPR group short name.
* <p>
* Note this excludes the "GROUP_" prefix.
* <p>
* 'package' scope to help testing.
*
* @param prefix prefix
* @param readers read authorities
* @param writers write authorities
* @param index group index
* @return String group short name
*/
/*package*/ String getIPRGroupShortName(String prefix, Set<String> authorities, int index)
{
return getIPRGroupShortName(prefix, authorities, Integer.toString(index));
}
/**
* Get IPR group short name.
* <p>
* Note this excludes the "GROUP_" prefix.
*
* @param prefix prefix
* @param readers read authorities
* @param writers write authorities
* @param index group index
* @return String group short name
*/
private String getIPRGroupShortName(String prefix, Set<String> authorities, String index)
{
StringBuilder builder = new StringBuilder(128)
.append(getIPRGroupPrefixShortName(prefix, authorities))
.append(index);
return builder.toString();
}
/**
* Gets the hashcode value of a set of authorities.
*
* @param authorities set of authorities
* @return int hash code
*/
private int getAuthoritySetHashCode(Set<String> authorities)
{
int result = 0;
if (authorities != null && !authorities.isEmpty())
{
result = StringUtils.join(authorities.toArray(), "").hashCode();
}
return result;
}
/**
* Creates a new IPR group.
*
* @param groupNamePrefix group name prefix
* @param children child authorities
* @param index group index
* @return String full name of created group
*/
private String createIPRGroup(String groupNamePrefix, Set<String> children, int index)
{
ParameterCheck.mandatory("groupNamePrefix", groupNamePrefix);
// get the group name
String groupShortName = getIPRGroupShortName(groupNamePrefix, children, index);
// create group
String group = authorityService.createAuthority(AuthorityType.GROUP, groupShortName, groupShortName, Collections.singleton(RMAuthority.ZONE_APP_RM));
// add root parent
authorityService.addAuthority(getRootIRPGroup(), group);
// add children if provided
if (children != null)
{
for (String child : children)
{
if (authorityService.authorityExists(child) &&
!PermissionService.ALL_AUTHORITIES.equals(child))
{
authorityService.addAuthority(group, child);
}
}
}
return group;
}
/**
* Assign IPR groups to a node reference with the correct permissions.
*
* @param iprGroups iprGroups, first read and second write
* @param nodeRef node reference
*/
private void assignIPRGroupsToNode(Pair<String, String> iprGroups, NodeRef nodeRef)
{
permissionService.setPermission(nodeRef, iprGroups.getFirst(), RMPermissionModel.READ_RECORDS, true);
permissionService.setPermission(nodeRef, iprGroups.getSecond(), RMPermissionModel.FILING, true);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#remove(org.alfresco.service.cmr.repository.NodeRef)
*/ */
@Override @Override
public void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String>writers, boolean applyToParents) public void remove(NodeRef nodeRef)
{ {
if (hasExtendedSecurity(nodeRef)) ParameterCheck.mandatory("nodeRef", nodeRef);
Pair<String, String> iprGroups = getIPRGroups(nodeRef);
if (iprGroups != null)
{ {
removeExtendedSecurityImpl(nodeRef, readers, writers); // remove any extended security that might be present
clearPermissions(nodeRef, iprGroups);
// remove the readers from any renditions of the content // remove the readers from any renditions of the content
if (isRecord(nodeRef)) if (isRecord(nodeRef))
@@ -297,110 +562,85 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
for (ChildAssociationRef assoc : assocs) for (ChildAssociationRef assoc : assocs)
{ {
NodeRef child = assoc.getChildRef(); NodeRef child = assoc.getChildRef();
removeExtendedSecurityImpl(child, readers, writers); clearPermissions(child, iprGroups);
}
}
if (applyToParents)
{
// apply the extended readers up the file plan primary hierarchy
NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef();
if (parent != null &&
filePlanService.isFilePlanComponent(parent))
{
removeExtendedSecurity(parent, readers, null, applyToParents);
removeExtendedSecurity(parent, writers, null, applyToParents);
} }
} }
} }
} }
/** /**
* Removes a set of readers and writers from a node reference. * Clear the nodes IPR permissions
* <p>
* Removes the aspect and resets the property to null if all readers and writers are removed.
* *
* @param nodeRef node reference * @param nodeRef node reference
* @param readers {@link Set} of readers
* @param writers {@link Set} of writers
*/ */
@SuppressWarnings("unchecked") private void clearPermissions(NodeRef nodeRef, Pair<String, String> iprGroups)
private void removeExtendedSecurityImpl(NodeRef nodeRef, Set<String> readers, Set<String> writers)
{ {
Map<String, Integer> readersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_READERS); // remove group permissions from node
nodeService.setProperty(nodeRef, PROP_READERS, (Serializable)removeFromMap(readersMap, readers)); permissionService.clearPermission(nodeRef, iprGroups.getFirst());
permissionService.clearPermission(nodeRef, iprGroups.getSecond());
Map<String, Integer> writersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_WRITERS);
nodeService.setProperty(nodeRef, PROP_WRITERS, (Serializable)removeFromMap(writersMap, writers));
if (readersMap == null && writersMap == null)
{
// remove the aspect
nodeService.removeAspect(nodeRef, ASPECT_EXTENDED_SECURITY);
}
} }
/** /**
* Helper method to remove items from map or reduce reference count * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#getExtendedReaders(org.alfresco.service.cmr.repository.NodeRef)
*
* @param map ref count map
* @param keys keys
* @return Map<String, Integer> ref count map
*/ */
private Map<String, Integer> removeFromMap(Map<String, Integer> map, Set<String> keys) @Override @Deprecated public Set<String> getExtendedReaders(NodeRef nodeRef)
{ {
if (map != null && keys != null && keys.size() != 0) return getReaders(nodeRef);
{
// remove the keys
for (String key : keys)
{
if (!key.equals(PermissionService.ALL_AUTHORITIES))
{
Integer count = map.get(key);
if (count != null)
{
if (count == 1)
{
// remove entry all together if the reference count is now 0
map.remove(key);
}
else
{
// decrement the reference count by 1
map.put(key, Integer.valueOf(count.intValue()-1));
}
}
}
}
}
// reset the map to null if now empty
if (map != null && map.isEmpty())
{
map = null;
}
return map;
} }
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#removeAllExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef) * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#getExtendedWriters(org.alfresco.service.cmr.repository.NodeRef)
*/ */
@Override @Override @Deprecated public Set<String> getExtendedWriters(NodeRef nodeRef)
public void removeAllExtendedSecurity(NodeRef nodeRef)
{ {
removeAllExtendedSecurity(nodeRef, true); return getWriters(nodeRef);
} }
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#removeAllExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, boolean) * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#addExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set)
*/ */
@Override @Override @Deprecated public void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers)
public void removeAllExtendedSecurity(NodeRef nodeRef, boolean applyToParents)
{ {
if (hasExtendedSecurity(nodeRef)) set(nodeRef, readers, writers);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#addExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set, boolean)
*/
@Override @Deprecated public void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents)
{ {
removeExtendedSecurity(nodeRef, getExtendedReaders(nodeRef), getExtendedWriters(nodeRef)); set(nodeRef, readers, writers);
} }
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#removeAllExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override @Deprecated public void removeAllExtendedSecurity(NodeRef nodeRef)
{
remove(nodeRef);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#removeExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set)
*/
@Override @Deprecated public void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers)
{
remove(nodeRef);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#removeExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set, boolean)
*/
@Override @Deprecated public void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String>writers, boolean applyToParents)
{
remove(nodeRef);
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#removeAllExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, boolean)
*/
@Override @Deprecated public void removeAllExtendedSecurity(NodeRef nodeRef, boolean applyToParents)
{
remove(nodeRef);
} }
} }

View File

@@ -27,8 +27,6 @@
package org.alfresco.module.org_alfresco_module_rm.security; package org.alfresco.module.org_alfresco_module_rm.security;
import static org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority.EXTENDED_READER;
import static org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority.EXTENDED_WRITER;
import static org.alfresco.repo.policy.Behaviour.NotificationFrequency.TRANSACTION_COMMIT; import static org.alfresco.repo.policy.Behaviour.NotificationFrequency.TRANSACTION_COMMIT;
import static org.alfresco.repo.policy.annotation.BehaviourKind.CLASS; import static org.alfresco.repo.policy.annotation.BehaviourKind.CLASS;
import static org.alfresco.repo.security.authentication.AuthenticationUtil.getSystemUserName; import static org.alfresco.repo.security.authentication.AuthenticationUtil.getSystemUserName;
@@ -383,13 +381,29 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
boolean inheritanceAllowed = isInheritanceAllowed(nodeRef, isParentNodeFilePlan); boolean inheritanceAllowed = isInheritanceAllowed(nodeRef, isParentNodeFilePlan);
getPermissionService().setInheritParentPermissions(nodeRef, inheritanceAllowed); getPermissionService().setInheritParentPermissions(nodeRef, inheritanceAllowed);
// clear all existing permissions Set<AccessPermission> keepPerms = new HashSet<AccessPermission>(5);
Set<AccessPermission> origionalPerms= getPermissionService().getAllSetPermissions(nodeRef);
for (AccessPermission perm : origionalPerms)
{
if (perm.getAuthority().startsWith(PermissionService.GROUP_PREFIX + ExtendedSecurityService.IPR_GROUP_PREFIX))
{
// then we can assume this is a permission we want to preserve
keepPerms.add(perm);
}
}
// clear all existing permissions and start again
getPermissionService().clearPermission(nodeRef, null); getPermissionService().clearPermission(nodeRef, null);
// re-add keep'er permissions
for (AccessPermission keeper : keepPerms)
{
setPermission(nodeRef, keeper.getAuthority(), keeper.getPermission());
}
if (!inheritanceAllowed) if (!inheritanceAllowed)
{ {
getPermissionService().setPermission(nodeRef, EXTENDED_READER, READ_RECORDS, true);
getPermissionService().setPermission(nodeRef, EXTENDED_WRITER, FILING, true);
String adminRole = getAdminRole(nodeRef); String adminRole = getAdminRole(nodeRef);
getPermissionService().setPermission(nodeRef, adminRole, RMPermissionModel.FILING, true); getPermissionService().setPermission(nodeRef, adminRole, RMPermissionModel.FILING, true);
} }
@@ -435,9 +449,20 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
return authorityService.getName(AuthorityType.GROUP, FilePlanRoleService.ROLE_ADMIN + filePlan.getId()); return authorityService.getName(AuthorityType.GROUP, FilePlanRoleService.ROLE_ADMIN + filePlan.getId());
} }
/**
* Indicates whether the default behaviour is to inherit permissions or not.
*
* @param nodeRef node reference
* @param isParentNodeFilePlan true if parent node is a file plan, false otherwise
* @return boolean true if inheritance true, false otherwise
*/
private boolean isInheritanceAllowed(NodeRef nodeRef, Boolean isParentNodeFilePlan) private boolean isInheritanceAllowed(NodeRef nodeRef, Boolean isParentNodeFilePlan)
{ {
return !(isFilePlan(nodeRef) || isTransfer(nodeRef) || isHold(nodeRef) || isUnfiledRecordsContainer(nodeRef) || (isRecordCategory(nodeRef) && isTrue(isParentNodeFilePlan))); return !(isFilePlan(nodeRef) ||
isTransfer(nodeRef) ||
isHold(nodeRef) ||
isUnfiledRecordsContainer(nodeRef) ||
(isRecordCategory(nodeRef) && isTrue(isParentNodeFilePlan)));
} }
/** /**
@@ -494,20 +519,14 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
for (AccessPermission recordPermission : origionalRecordPerms) for (AccessPermission recordPermission : origionalRecordPerms)
{ {
String permission = recordPermission.getPermission(); String permission = recordPermission.getPermission();
String authority = recordPermission.getAuthority();
if ((RMPermissionModel.FILING.equals(permission) || RMPermissionModel.READ_RECORDS.equals(permission)) && if ((RMPermissionModel.FILING.equals(permission) || RMPermissionModel.READ_RECORDS.equals(permission)) &&
recordPermission.isSetDirectly() && recordPermission.isSetDirectly())
!ExtendedReaderDynamicAuthority.EXTENDED_READER.equals(authority) &&
!ExtendedWriterDynamicAuthority.EXTENDED_WRITER.equals(authority))
{ {
// then we can assume this is a permission we want to preserve // then we can assume this is a permission we want to preserve
keepPerms.add(recordPermission); keepPerms.add(recordPermission);
} }
} }
// clear all existing permissions and start again
permissionService.deletePermissions(record);
// re-setup the records permissions // re-setup the records permissions
setupPermissions(destinationAssocRef.getParentRef(), record); setupPermissions(destinationAssocRef.getParentRef(), record);
@@ -589,7 +608,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
private boolean canPerformPermissionAction(NodeRef nodeRef) private boolean canPerformPermissionAction(NodeRef nodeRef)
{ {
return isFilePlanContainer(nodeRef) || isRecordFolder(nodeRef) || isRecord(nodeRef) || isTransfer(nodeRef); return isFilePlanContainer(nodeRef) || isRecordFolder(nodeRef) || isRecord(nodeRef) || isTransfer(nodeRef) || isHold(nodeRef);
} }
/** /**

View File

@@ -34,7 +34,6 @@ import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -56,12 +55,12 @@ import org.alfresco.repo.version.VersionModel;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.version.ReservedVersionNameException; import org.alfresco.service.cmr.version.ReservedVersionNameException;
import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionHistory; import org.alfresco.service.cmr.version.VersionHistory;
import org.alfresco.service.cmr.version.VersionType; import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyMap; import org.alfresco.util.PropertyMap;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@@ -130,9 +129,6 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
/** extended security service */ /** extended security service */
private ExtendedSecurityService extendedSecurityService; private ExtendedSecurityService extendedSecurityService;
/** ownable service */
private OwnableService ownableService;
/** /**
* @param filePlanService file plan service * @param filePlanService file plan service
*/ */
@@ -197,14 +193,6 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
this.extendedSecurityService = extendedSecurityService; this.extendedSecurityService = extendedSecurityService;
} }
/**
* @param ownableService ownable service
*/
public void setOwnableService(OwnableService ownableService)
{
this.ownableService = ownableService;
}
/** /**
* @see org.alfresco.repo.version.Version2ServiceImpl#createVersion(org.alfresco.service.cmr.repository.NodeRef, java.util.Map, int) * @see org.alfresco.repo.version.Version2ServiceImpl#createVersion(org.alfresco.service.cmr.repository.NodeRef, java.util.Map, int)
*/ */
@@ -706,13 +694,8 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
{ {
public NodeRef doWork() throws Exception public NodeRef doWork() throws Exception
{ {
// get the documents readers // get the documents readers and writers
Long aclId = nodeService.getNodeAclId(nodeRef); Pair<Set<String>, Set<String>> readersAndWriters = extendedPermissionService.getReadersAndWriters(nodeRef);
Set<String> readers = extendedPermissionService.getReaders(aclId);
Set<String> writers = extendedPermissionService.getWriters(aclId);
// add the current owner to the list of extended writers
String owner = ownableService.getOwner(nodeRef);
// grab the frozen state // grab the frozen state
NodeRef currentFrozenState = currentVersion.getFrozenStateNodeRef(); NodeRef currentFrozenState = currentVersion.getFrozenStateNodeRef();
@@ -752,13 +735,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
linkToPreviousVersionRecord(nodeRef, record); linkToPreviousVersionRecord(nodeRef, record);
// set the extended security // set the extended security
Set<String> combinedWriters = new HashSet<String>(writers); extendedSecurityService.set(record, readersAndWriters);
if (owner != null && !owner.isEmpty() && !owner.equals(OwnableService.NO_OWNER))
{
combinedWriters.add(owner);
}
combinedWriters.add(authenticationUtil.getFullyAuthenticatedUser());
extendedSecurityService.addExtendedSecurity(record, readers, combinedWriters);
return record; return record;
} }

View File

@@ -29,7 +29,9 @@ package org.alfresco.repo.security.permissions.impl;
import java.util.Set; import java.util.Set;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.util.Pair;
/** /**
* Extended Permission Service Interface used in RM. * Extended Permission Service Interface used in RM.
@@ -46,4 +48,18 @@ public interface ExtendedPermissionService extends PermissionService
* @return {@link Set}<{@link String}> set of authorities with write access * @return {@link Set}<{@link String}> set of authorities with write access
*/ */
Set<String> getWriters(Long aclId); Set<String> getWriters(Long aclId);
/**
* Get the readers and writers for a given node.
* <p>
* The writers list includes the owner for the node.
*
* @param nodeRef node reference
* @return Pair<Set<String>, Set<String>> first is a set containing all the authorities that have read permission on the
* document and second is a set containing all the authorities that have write
* permission on the document, including the owner.
*
* @since 2.5
*/
Pair<Set<String>, Set<String>> getReadersAndWriters(NodeRef nodeRef);
} }

View File

@@ -39,8 +39,6 @@ import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService; import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.security.permissions.AccessControlEntry; import org.alfresco.repo.security.permissions.AccessControlEntry;
import org.alfresco.repo.security.permissions.AccessControlList; import org.alfresco.repo.security.permissions.AccessControlList;
@@ -50,8 +48,11 @@ import org.alfresco.repo.security.permissions.processor.PermissionProcessorRegis
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyCheck; import org.alfresco.util.PropertyCheck;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
/** /**
@@ -359,13 +360,17 @@ public class ExtendedPermissionServiceImpl extends PermissionServiceImpl
final String adminRole = getAdminRole(nodeRef); final String adminRole = getAdminRole(nodeRef);
if (nodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT) && isNotBlank(adminRole) && !inheritParentPermissions) if (nodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT) && isNotBlank(adminRole) && !inheritParentPermissions)
{ {
setPermission(nodeRef, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true);
setPermission(nodeRef, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true);
setPermission(nodeRef, adminRole, RMPermissionModel.FILING, true); setPermission(nodeRef, adminRole, RMPermissionModel.FILING, true);
} }
super.setInheritParentPermissions(nodeRef, inheritParentPermissions); super.setInheritParentPermissions(nodeRef, inheritParentPermissions);
} }
/**
* Helper method to the RM admin role scoped by the correct file plan.
*
* @param nodeRef node reference
* @return String RM admin role
*/
private String getAdminRole(NodeRef nodeRef) private String getAdminRole(NodeRef nodeRef)
{ {
String adminRole = null; String adminRole = null;
@@ -376,4 +381,28 @@ public class ExtendedPermissionServiceImpl extends PermissionServiceImpl
} }
return adminRole; return adminRole;
} }
/**
* @see org.alfresco.repo.security.permissions.impl.ExtendedPermissionService#getReadersAndWriters(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
public Pair<Set<String>, Set<String>> getReadersAndWriters(NodeRef nodeRef)
{
// get the documents readers
Long aclId = nodeService.getNodeAclId(nodeRef);
Set<String> readers = getReaders(aclId);
Set<String> writers = getWriters(aclId);
// add the current owner to the list of extended writers
Set<String> modifiedWrtiers = new HashSet<String>(writers);
String owner = ownableService.getOwner(nodeRef);
if (StringUtils.isNotBlank(owner) &&
!owner.equals(OwnableService.NO_OWNER) &&
authorityService.authorityExists(owner))
{
modifiedWrtiers.add(owner);
}
return new Pair<Set<String>, Set<String>> (readers, modifiedWrtiers);
}
} }

View File

@@ -0,0 +1,267 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* Copyright (C) 2005-2014 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.repo.web.scripts.roles;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.patch.PatchDAO;
import org.alfresco.repo.domain.qname.QNameDAO;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.Pair;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* Webscript used for removing dynamic authorities from the records.
*
* @author Silviu Dinuta
* @since 2.3.0.7
*/
@SuppressWarnings("deprecation")
public class DynamicAuthoritiesGet extends DeclarativeWebScript implements RecordsManagementModel
{
private static final String MESSAGE_PARAMETER_BATCHSIZE_GREATER_THAN_ZERO = "Parameter batchsize should be a number greater than 0.";
private static final String MESSAGE_PROCESSING_BEGIN = "Processing - BEGIN";
private static final String MESSAGE_PROCESSING_END = "Processing - END";
private static final String MESSAGE_PROCESSING_RECORD_END_TEMPLATE = "Processing record {0} - END";
private static final String MESSAGE_PROCESSING_RECORD_BEGIN_TEMPLATE = "Processing record {0} - BEGIN";
private static final String MESSAGE_BATCHSIZE_IS_INVALID = "Parameter batchsize is invalid.";
private static final String MESSAGE_BATCHSIZE_IS_MANDATORY = "Parameter batchsize is mandatory";
private static final String SUCCESS_STATUS = "success";
private static final String FAILED_STATUS = "failed";
/**
* The logger
*/
private static Log logger = LogFactory.getLog(DynamicAuthoritiesGet.class);
private static final String BATCH_SIZE = "batchsize";
private static final String TOTAL_NUMBER_TO_PROCESS = "maxProcessedRecords";
private static final String MODEL_STATUS = "responsestatus";
private static final String MODEL_MESSAGE = "message";
private static final String MESSAGE_ALL_TEMPLATE = "Processed {0} records.";
private static final String MESSAGE_PARTIAL_TEMPLATE = "Processed first {0} records.";
private static final String MESSAGE_NO_RECORDS_TO_PROCESS = "There where no records to be processed.";
/** services */
private PatchDAO patchDAO;
private NodeDAO nodeDAO;
private QNameDAO qnameDAO;
private NodeService nodeService;
private PermissionService permissionService;
private ExtendedSecurityService extendedSecurityService;
private TransactionService transactionService;
/** service setters */
public void setPatchDAO(PatchDAO patchDAO) { this.patchDAO = patchDAO; }
public void setNodeDAO(NodeDAO nodeDAO) { this.nodeDAO = nodeDAO; }
public void setQnameDAO(QNameDAO qnameDAO) { this.qnameDAO = qnameDAO; }
public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; }
public void setPermissionService(PermissionService permissionService) { this.permissionService = permissionService; }
public void setExtendedSecurityService(ExtendedSecurityService extendedSecurityService) { this.extendedSecurityService = extendedSecurityService; }
public void setTransactionService(TransactionService transactionService) { this.transactionService = transactionService; }
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
Map<String, Object> model = new HashMap<String, Object>();
String batchSizeStr = req.getParameter(BATCH_SIZE);
String totalToBeProcessedRecordsStr = req.getParameter(TOTAL_NUMBER_TO_PROCESS);
Long size = 0L;
if (StringUtils.isBlank(batchSizeStr))
{
model.put(MODEL_STATUS, FAILED_STATUS);
model.put(MODEL_MESSAGE, MESSAGE_BATCHSIZE_IS_MANDATORY);
logger.info(MESSAGE_BATCHSIZE_IS_MANDATORY);
return model;
}
try
{
size = Long.parseLong(batchSizeStr);
if(size <= 0)
{
model.put(MODEL_STATUS, FAILED_STATUS);
model.put(MODEL_MESSAGE, MESSAGE_PARAMETER_BATCHSIZE_GREATER_THAN_ZERO);
logger.info(MESSAGE_PARAMETER_BATCHSIZE_GREATER_THAN_ZERO);
return model;
}
}
catch(NumberFormatException ex)
{
model.put(MODEL_STATUS, FAILED_STATUS);
model.put(MODEL_MESSAGE, MESSAGE_BATCHSIZE_IS_INVALID);
logger.info(MESSAGE_BATCHSIZE_IS_INVALID);
return model;
}
final Long batchSize = size;
// get the max node id and the extended security aspect
Long maxNodeId = patchDAO.getMaxAdmNodeID();
final Pair<Long, QName> recordAspectPair = qnameDAO.getQName(ASPECT_EXTENDED_SECURITY);
if(recordAspectPair == null)
{
model.put(MODEL_STATUS, SUCCESS_STATUS);
model.put(MODEL_MESSAGE, MESSAGE_NO_RECORDS_TO_PROCESS);
logger.info(MESSAGE_NO_RECORDS_TO_PROCESS);
return model;
}
//default total number of records to be processed to batch size value
Long totalNumberOfRecordsToProcess = batchSize;
if (StringUtils.isNotBlank(totalToBeProcessedRecordsStr))
{
try
{
totalNumberOfRecordsToProcess = Long.parseLong(totalToBeProcessedRecordsStr);
}
catch(NumberFormatException ex)
{
//do nothing here, the value will remain 0L in this case
}
}
final Long maxRecordsToProcess = totalNumberOfRecordsToProcess;
final List<NodeRef> processedNodes = new ArrayList<NodeRef>();
logger.info(MESSAGE_PROCESSING_BEGIN);
// by batch size
for (Long i = 0L; i < maxNodeId; i+=batchSize)
{
if(maxRecordsToProcess != 0 && processedNodes.size() >= maxRecordsToProcess)
{
break;
}
final Long currentIndex = i;
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
{
// get the nodes with the extended security aspect applied
List<Long> nodeIds = patchDAO.getNodesByAspectQNameId(recordAspectPair.getFirst(), currentIndex, currentIndex + batchSize);
// process each one
for (Long nodeId : nodeIds)
{
if(maxRecordsToProcess != 0 && processedNodes.size() >= maxRecordsToProcess)
{
break;
}
NodeRef record = nodeDAO.getNodePair(nodeId).getSecond();
String recordName = (String) nodeService.getProperty(record, ContentModel.PROP_NAME);
logger.info(MessageFormat.format(MESSAGE_PROCESSING_RECORD_BEGIN_TEMPLATE, recordName));
processNode(record);
logger.info(MessageFormat.format(MESSAGE_PROCESSING_RECORD_END_TEMPLATE, recordName));
processedNodes.add(record);
}
return null;
}
},
false, // read only
true); // requires new
}
logger.info(MESSAGE_PROCESSING_END);
int processedNodesSize = processedNodes.size();
String message = "";
if(totalNumberOfRecordsToProcess == 0 || (totalNumberOfRecordsToProcess > 0 && processedNodesSize < totalNumberOfRecordsToProcess))
{
message = MessageFormat.format(MESSAGE_ALL_TEMPLATE, processedNodesSize);
}
if (totalNumberOfRecordsToProcess > 0 && totalNumberOfRecordsToProcess == processedNodesSize)
{
message = MessageFormat.format(MESSAGE_PARTIAL_TEMPLATE, totalNumberOfRecordsToProcess);
}
model.put(MODEL_STATUS, SUCCESS_STATUS);
model.put(MODEL_MESSAGE, message);
logger.info(message);
return model;
}
/**
* Process each node
*
* @param nodeRef
*/
@SuppressWarnings({ "unchecked"})
private void processNode(NodeRef nodeRef)
{
// get the reader/writer data
Map<String, Integer> readers = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_READERS);
Map<String, Integer> writers = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_WRITERS);
// remove extended security aspect
nodeService.removeAspect(nodeRef, ASPECT_EXTENDED_SECURITY);
// remove dynamic authority permissions
permissionService.clearPermission(nodeRef, ExtendedReaderDynamicAuthority.EXTENDED_READER);
permissionService.clearPermission(nodeRef, ExtendedWriterDynamicAuthority.EXTENDED_WRITER);
// if record then ...
if (nodeService.hasAspect(nodeRef, ASPECT_RECORD))
{
// re-set extended security via API
extendedSecurityService.set(nodeRef, readers.keySet(), writers.keySet());
}
}
}

View File

@@ -44,14 +44,14 @@ public class RM1429Test extends DeleteHoldTest
{ {
public void testDeleteHoldWithoutPermissionsOnChildren() public void testDeleteHoldWithoutPermissionsOnChildren()
{ {
// Create the test hold final NodeRef hold = doTestInTransaction(new Test<NodeRef>()
final NodeRef hold = createAndCheckHold();
doTestInTransaction(new Test<Void>()
{ {
@Override @Override
public Void run() public NodeRef run()
{ {
// Create the test hold
NodeRef hold = createAndCheckHold();
// Add the user to the RM Manager role // Add the user to the RM Manager role
filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_RECORDS_MANAGER, userName); filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_RECORDS_MANAGER, userName);
@@ -64,7 +64,7 @@ public class RM1429Test extends DeleteHoldTest
// Add record folder to the hold // Add record folder to the hold
holdService.addToHold(hold, rmFolder); holdService.addToHold(hold, rmFolder);
return null; return hold;
} }
}); });

View File

@@ -44,14 +44,14 @@ public class RM1463Test extends DeleteHoldTest
{ {
public void testAddRecordFolderToHoldWithoutFilingPermissionOnRecordFolder() public void testAddRecordFolderToHoldWithoutFilingPermissionOnRecordFolder()
{ {
// Create hold final NodeRef hold = doTestInTransaction(new Test<NodeRef>()
final NodeRef hold = createAndCheckHold();
doTestInTransaction(new Test<Void>()
{ {
@Override @Override
public Void run() public NodeRef run()
{ {
// Create hold
NodeRef hold = createAndCheckHold();
// Add the user to the RM Manager role // Add the user to the RM Manager role
filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_RECORDS_MANAGER, userName); filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_RECORDS_MANAGER, userName);
@@ -61,7 +61,7 @@ public class RM1463Test extends DeleteHoldTest
// Give the user only read permissions on the record folder // Give the user only read permissions on the record folder
permissionService.setPermission(rmFolder, userName, RMPermissionModel.READ_RECORDS, true); permissionService.setPermission(rmFolder, userName, RMPermissionModel.READ_RECORDS, true);
return null; return hold;
} }
}); });

View File

@@ -44,14 +44,14 @@ public class RM1464Test extends DeleteHoldTest
{ {
public void testAddRecordFolderToHoldWithoutFilingPermissionOnHold() public void testAddRecordFolderToHoldWithoutFilingPermissionOnHold()
{ {
// Create hold final NodeRef hold = doTestInTransaction(new Test<NodeRef>()
final NodeRef hold = createAndCheckHold();
doTestInTransaction(new Test<Void>()
{ {
@Override @Override
public Void run() public NodeRef run()
{ {
// Create hold
NodeRef hold = createAndCheckHold();
// Add the user to the RM Manager role // Add the user to the RM Manager role
filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_RECORDS_MANAGER, userName); filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_RECORDS_MANAGER, userName);
@@ -61,7 +61,7 @@ public class RM1464Test extends DeleteHoldTest
// Give the user filing permissions on the record folder // Give the user filing permissions on the record folder
permissionService.setPermission(rmFolder, userName, RMPermissionModel.FILING, true); permissionService.setPermission(rmFolder, userName, RMPermissionModel.FILING, true);
return null; return hold;
} }
}); });

View File

@@ -0,0 +1,253 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* Copyright (C) 2005-2014 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.test.integration.issue;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.action.dm.CreateRecordAction;
import org.alfresco.module.org_alfresco_module_rm.action.impl.FileToAction;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.rule.Rule;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.rule.RuleType;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
/**
* System test for RM-3993: Exceptions thrown when concurrently creating identical folder structure
*
* @author Silviu Dinuta
* @since 2.3.0.7
*/
public class RM3993Test extends BaseRMTestCase
{
private static final int NUMBER_OF_BATCHES = 4;
private static final int NUMBER_IN_BATCH = 500;
private RuleService ruleService;
private NodeRef ruleFolder;
private NodeRef nodeRefCategory1;
@Override
protected void initServices()
{
super.initServices();
ruleService = (RuleService) applicationContext.getBean("RuleService");
}
@Override
protected boolean isCollaborationSiteTest()
{
return true;
}
@Override
protected boolean isRecordTest()
{
return true;
}
/**
* Given that I have auto declare configured And that I have auto file configured to a path where only the record
* folder needs to be created When I add lots of documents in the same transaction Then the rules should fire And
* the documents should be filed in the new record folder
*/
public void testAutoDeclareAutoFileCreateRecordFolderOnly() throws Exception
{
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
// create the folder
ruleFolder = fileFolderService.create(documentLibrary, "mytestfolder", ContentModel.TYPE_FOLDER)
.getNodeRef();
// create record category
nodeRefCategory1 = filePlanService.createRecordCategory(filePlan, "category1");
Action action = actionService.createAction(CreateRecordAction.NAME);
action.setParameterValue(CreateRecordAction.PARAM_FILE_PLAN, filePlan);
Rule rule = new Rule();
rule.setRuleType(RuleType.INBOUND);
rule.setTitle("my rule");
rule.setAction(action);
rule.setExecuteAsynchronously(true);
ruleService.saveRule(ruleFolder, rule);
Action fileAction = actionService.createAction(FileToAction.NAME);
fileAction.setParameterValue(FileToAction.PARAM_PATH,
"/category1/{node.cm:description}");
fileAction.setParameterValue(FileToAction.PARAM_CREATE_RECORD_PATH, true);
Rule fileRule = new Rule();
fileRule.setRuleType(RuleType.INBOUND);
fileRule.setTitle("my rule");
fileRule.setAction(fileAction);
fileRule.setExecuteAsynchronously(true);
ruleService.saveRule(filePlanService.getUnfiledContainer(filePlan), fileRule);
return null;
}
@Override
public void test(Void result) throws Exception
{
assertFalse(ruleService.getRules(ruleFolder).isEmpty());
}
});
List<NodeRef> records = new ArrayList<NodeRef>(NUMBER_OF_BATCHES * NUMBER_IN_BATCH);
for (int i = 0; i < NUMBER_OF_BATCHES; i++)
{
final int finali = i;
records.addAll(doTestInTransaction(new Test<List<NodeRef>>()
{
@Override
public List<NodeRef> run() throws Exception
{
List<NodeRef> records = new ArrayList<NodeRef>(NUMBER_IN_BATCH);
for (int j = 0; j < NUMBER_IN_BATCH; j++)
{
int count = (finali)* NUMBER_IN_BATCH + (j + 1);
String name = "content" + count + ".txt";
System.out.println(name + " - creating");
Random rand = new Random();
int descInt = rand.nextInt(2)+1;
NodeRef record = createFile(ruleFolder, name, Integer.toString(descInt), ContentModel.TYPE_CONTENT);
records.add(record);
}
return records;
}
}));
}
try
{
while (!records.isEmpty())
{
Thread.sleep(1000);
final Iterator<NodeRef> temp = records.iterator();
doTestInTransaction(new Test<Void>()
{
@Override
public Void run() throws Exception
{
while (temp.hasNext())
{
NodeRef record = temp.next();
if (nodeService.hasAspect(record, ASPECT_RECORD) && recordService.isFiled(record))
{
String name = (String) nodeService.getProperty(record, ContentModel.PROP_NAME);
System.out.println(name + " - complete");
temp.remove();
}
}
return null;
}
});
}
}
catch (Exception exception)
{
exception.printStackTrace();
throw exception;
}
Integer numberOfRecords = AuthenticationUtil.runAsSystem(new RunAsWork<Integer>()
{
@Override
public Integer doWork() throws Exception
{
List<NodeRef> containedRecordFolders = filePlanService.getContainedRecordFolders(nodeRefCategory1);
int numberOfRecords = 0;
for(NodeRef recordFolder : containedRecordFolders)
{
numberOfRecords = numberOfRecords + fileFolderService.list(recordFolder).size();
}
return numberOfRecords;
}
});
assertTrue(numberOfRecords == NUMBER_OF_BATCHES * NUMBER_IN_BATCH);
}
private NodeRef createFile(NodeRef parentNodeRef, String name, String descrption, QName typeQName)
{
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(11);
properties.put(ContentModel.PROP_NAME, (Serializable) name);
properties.put(ContentModel.PROP_DESCRIPTION, (Serializable) descrption);
QName assocQName = QName.createQName(
NamespaceService.CONTENT_MODEL_1_0_URI,
QName.createValidLocalName(name));
ChildAssociationRef assocRef = nodeService.createNode(
parentNodeRef,
ContentModel.ASSOC_CONTAINS,
assocQName,
typeQName,
properties);
NodeRef nodeRef = assocRef.getChildRef();
return nodeRef;
}
}

View File

@@ -0,0 +1,188 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.test.integration.record;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.security.AccessStatus;
/**
* Create Inplace Record Test
*
* @author Roy Wetherall
*/
public class CreateInplaceRecordTest extends BaseRMTestCase
{
@Override
protected boolean isCollaborationSiteTest()
{
return true;
}
/**
* Given a document in a collaboration site
* When the document is declared by a site collaborator
* Then the document becomes a record
* And the site users have the appropriate in-place permissions on the record
*/
public void testCreateInplaceRecordFromCollabSite()
{
doBehaviourDrivenTest(new BehaviourDrivenTest()
{
public void given()
{
// Check that the document is not a record
assertFalse("The document should not be a record", recordService.isRecord(dmDocument));
}
public void when()
{
// Declare the document as a record
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
// Declare record
recordService.createRecord(filePlan, dmDocument);
return null;
}
}, dmCollaborator);
}
public void then()
{
// Check that the document is a record now
assertTrue("The document should now be a record", recordService.isRecord(dmDocument));
// Check that the record is in the unfiled container
// Check that the record is still a child of the collaboration folder
// Check that the collaborator has filling permissions on the record
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(dmDocument, RMPermissionModel.FILING));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(dmDocument, RMPermissionModel.READ_RECORDS));
return null;
}
}, dmCollaborator);
// Check that the consumer has read permissions on the record
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(dmDocument, RMPermissionModel.FILING));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(dmDocument, RMPermissionModel.READ_RECORDS));
return null;
}
}, dmConsumer);
}
});
}
public void testFileInplaceRecordFromCollabSite()
{
doBehaviourDrivenTest(new BehaviourDrivenTest()
{
public void given()
{
// Check that the document is not a record
assertFalse("The document should not be a record", recordService.isRecord(dmDocument));
// Declare the document as a record
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
// Declare record
recordService.createRecord(filePlan, dmDocument);
return null;
}
}, dmCollaborator);
// Check that the document is a record
assertTrue("The document should be a record", recordService.isRecord(dmDocument));
assertFalse("The record should not be filed", recordService.isFiled(dmDocument));
}
public void when() throws FileExistsException, FileNotFoundException
{
// file the document to a location in the file plan
fileFolderService.move(dmDocument, rmFolder, null);
}
public void then()
{
// Check that the document is a record now
assertTrue("The document should be a record", recordService.isRecord(dmDocument));
assertTrue("The record hsould be filed", recordService.isFiled(dmDocument));
// Check that the record is in the unfiled container
// TODO
// Check that the record is still a child of the collaboration folder
// TODO
// Check that the collaborator has filling permissions on the record
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(dmDocument, RMPermissionModel.FILING));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(dmDocument, RMPermissionModel.READ_RECORDS));
return null;
}
}, dmCollaborator);
// Check that the consumer has read permissions on the record
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(dmDocument, RMPermissionModel.FILING));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(dmDocument, RMPermissionModel.READ_RECORDS));
return null;
}
}, dmConsumer);
}
});
}
}

View File

@@ -0,0 +1,951 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.test.integration.record;
import static org.alfresco.module.org_alfresco_module_rm.test.util.bdt.BehaviourTest.test;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.action.impl.CutOffAction;
import org.alfresco.module.org_alfresco_module_rm.action.impl.DeclareRecordAction;
import org.alfresco.module.org_alfresco_module_rm.action.impl.DestroyAction;
import org.alfresco.module.org_alfresco_module_rm.capability.Capability;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils;
import org.alfresco.module.org_alfresco_module_rm.test.util.bdt.BehaviourTest;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.site.SiteModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.util.GUID;
/**
* In-place record permission integration test.
*
* @author Roy Wetherall
* @since 2.5
*/
public class InplaceRecordPermissionTest extends BaseRMTestCase
{
/** capability list */
private static final List<String> CAPABILITIES = Stream
.of(RMPermissionModel.VIEW_RECORDS,
RMPermissionModel.EDIT_NON_RECORD_METADATA,
RMPermissionModel.EDIT_RECORD_METADATA)
.collect(Collectors.toList());
/** test data */
private NodeRef contribDoc;
private NodeRef deleteUserDoc;
private NodeRef copiedDoc;
private NodeRef copyDoc;
private String deletedUser;
/** services */
private NodeService dbNodeService;
/** capabilities */
private Capability viewRecordsCapability;
private Capability editNonRecordMetadataCapability;
private Capability editRecordMetadataCapability;
/** test characteristics */
@Override protected boolean isCollaborationSiteTest() { return true; }
@Override protected boolean isUserTest() { return true; }
/**
* @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#initServices()
*/
@Override
protected void initServices()
{
super.initServices();
// initialise behaviour tests
BehaviourTest.initBehaviourTests(retryingTransactionHelper);
// get services
dbNodeService = (NodeService)applicationContext.getBean("dbNodeService");
// get capability references
viewRecordsCapability = capabilityService.getCapability(RMPermissionModel.VIEW_RECORDS);
editNonRecordMetadataCapability = capabilityService.getCapability(RMPermissionModel.EDIT_NON_RECORD_METADATA);
editRecordMetadataCapability = capabilityService.getCapability(RMPermissionModel.EDIT_RECORD_METADATA);
}
/**
* Given a document in a collaboration site
* When a user without write permissions on the document tries to declare it as a record
* Then the declaration fails
* And the document does not become a record
*/
public void testUserWithOutWriteCantDeclareInPlaceRecord()
{
test()
.given()
// Given a document in a collaboration site that is not a record
.expect(false)
.from(() -> recordService.isRecord(dmDocument))
.because("The document is not a record.")
// And a user with no write permission on the document
.as(userName)
.expect(AccessStatus.DENIED.toString())
.from(() -> permissionService.hasPermission(dmDocument, PermissionService.WRITE).toString())
.because("User does not have write access to document.")
// When the user tries to declare the record
// Then we expect this to fail
.when()
.as(userName)
.expectException(AccessDeniedException.class)
.from(() -> recordService.createRecord(filePlan, dmDocument))
.because("The user does not have write permission on the document.");
}
/**
* Given a document in a collaboration site that is not a record
* And a contributor the didn't create the document
* When the contributor tries to declare the document as a record
* Then the document does not become a record
*/
public void testContributorThatIsntOwnerDeclareInPlaceRecord()
{
test()
.given()
// Given a document in a collaboration site that is not a record
.expect(false)
.from(() -> recordService.isRecord(dmDocument))
.because("The document is not a record.")
// And a contributor the didn't create the document
.as(dmContributor)
.expect(AccessStatus.DENIED.toString())
.from(() -> permissionService.hasPermission(dmDocument, PermissionService.WRITE).toString())
.because("Contributor does not have write access to document.")
// When the user tries to declare the record
// When the contributor tries to declare the document as a record
.when()
.as(dmContributor)
.expectException(AccessDeniedException.class)
.from(() -> recordService.createRecord(filePlan, dmDocument))
.because("The contributor does not have write permission on the document.");
}
/**
* Given a document in a collaboration site is not a record
* When the document is declared by a site collaborator
* Then the document becomes a record
* And the site users have the appropriate in-place permissions on the record
*/
public void testCreateInplaceRecordFromCollabSite()
{
test()
// Given that a document in a collaboration site is not a record
.given()
.asAdmin()
.expect(false)
.from(() -> recordService.isRecord(dmDocument))
.because("The document is not a record")
// When it is declared as an inplace record
.when()
.as(dmCollaborator)
.perform(() -> recordService.createRecord(filePlan, dmDocument))
.then()
.asAdmin()
// Then it becomes a record
.expect(true)
.from(() -> recordService.isRecord(dmDocument))
.because("The document is a record")
// And it isn't filed
.expect(false)
.from(() -> recordService.isFiled(dmDocument))
.because("The record is not filed")
// And a site collaborator has filling permissions and filling capability on the record
.as(dmCollaborator)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.ALLOWED, // read record permission
AccessStatus.ALLOWED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.ALLOWED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a site contributor has read and view
.as(dmContributor)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.ALLOWED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a site consumer has read permissions and view record capability on the record
.as(dmConsumer)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.ALLOWED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a user that is not a member of the site has no access to the inplace record
.as(userName)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)); // edit record metadata capability
}
/**
* Helper method to check in place access for a user on a record.
*/
private void checkInPlaceAccess(NodeRef nodeRef, AccessStatus ... accessStatus)
{
// check permission access
assertEquals("Incorrect read record permission access.", accessStatus[0], permissionService.hasPermission(nodeRef, RMPermissionModel.READ_RECORDS));
assertEquals("Incorrect filling permission access.", accessStatus[1], permissionService.hasPermission(nodeRef, RMPermissionModel.FILING));
// check capability access
Map<Capability, AccessStatus> access = capabilityService.getCapabilitiesAccessState(nodeRef, CAPABILITIES);
assertEquals("Incorrect view records capability access", accessStatus[2], access.get(viewRecordsCapability));
assertEquals("Incorrect edit non record metadata capability access", accessStatus[3], access.get(editNonRecordMetadataCapability));
assertEquals("Incorrect edit record metadata capability access", accessStatus[4], access.get(editRecordMetadataCapability));
}
/**
* Given that a document is created by contributor
* When it is declared as an inplace record
* Then it becomes a record
* And it isn't filed
* And a site collaborator has filling permissions and filling capability on the record
* And a site contributor has filling capability and permissions
* And a site consumer has read permissions and view record capability on the record
* And a user that is not a member of the site has no access to the inplace record
*/
public void testCreateInplaceRecordFromCollabSiteWhenContribIsCreatorOfDocument()
{
test()
// Given that a document is created by contributor
.given()
.as(dmContributor)
.perform(() ->
{
contribDoc = fileFolderService.create(dmFolder, "contrib.txt" , ContentModel.TYPE_CONTENT).getNodeRef();
dbNodeService.addAspect(contribDoc, ContentModel.ASPECT_AUDITABLE, null);
})
.expect(false)
.from(() -> recordService.isRecord(contribDoc))
.because("It is not a record.")
.asAdmin()
.expect(dmContributor)
.from(() -> ownableService.getOwner(contribDoc))
.because("As the creator of the document the contributor is also the owner")
.as(dmContributor)
.expect(AccessStatus.ALLOWED.toString())
.from(() -> permissionService.hasPermission(contribDoc, PermissionService.WRITE).toString())
.because("Contrib user has write permissions on created document as the owner.")
// When it is declared as an inplace record
.when()
.as(dmContributor)
.perform(() -> recordService.createRecord(filePlan, contribDoc))
.then()
.asAdmin()
// Then it becomes a record
.expect(true)
.from(() -> recordService.isRecord(contribDoc))
.because("The document is a record")
// And it isn't filed
.expect(false)
.from(() -> recordService.isFiled(contribDoc))
.because("The record is not filed")
// And a site collaborator has filling permissions and filling capability on the record
.as(dmCollaborator)
.perform(() ->
checkInPlaceAccess(contribDoc,
AccessStatus.ALLOWED, // read record permission
AccessStatus.ALLOWED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.ALLOWED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a site contributor has filling capability and permissions
.as(dmContributor)
.perform(() ->
checkInPlaceAccess(contribDoc,
AccessStatus.ALLOWED, // read record permission
AccessStatus.ALLOWED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.ALLOWED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a site consumer has read permissions and view record capability on the record
.as(dmConsumer)
.perform(() ->
checkInPlaceAccess(contribDoc,
AccessStatus.ALLOWED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a user that is not a member of the site has no access to the inplace record
.as(userName)
.perform(() ->
checkInPlaceAccess(contribDoc,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)); // edit record metadata capability
}
/**
* Given an unfiled in-place record
* When the record is moved to the file plan (ie filed)
* Then the site users still have the appropriate in-place permissions on the record
*/
public void testFileInplaceRecordFromCollabSite() throws Exception
{
test()
// Given an unfiled inplace record
.given()
.as(dmCollaborator)
.perform(() -> recordService.createRecord(filePlan, dmDocument))
.expect(true)
.from(() -> recordService.isRecord(dmDocument))
.because("The document is a record.")
.expect(false)
.from(() -> recordService.isFiled(dmDocument))
.because("The record is not filed")
// When the record is filed
.when()
.asAdmin()
.perform(() -> fileFolderService.move(dmDocument, rmFolder, null))
.then()
// Then the record is filed
.asAdmin()
.expect(true)
.from(() -> recordService.isFiled(dmDocument))
.because("The record is filed.")
// And the collaborator has filling permissions and filling capability on the record
.as(dmCollaborator)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.ALLOWED, // read record permission
AccessStatus.ALLOWED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.ALLOWED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a site contributor has read and view
.as(dmContributor)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.ALLOWED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And the consumer has read permissions and view record capability on the record
.as(dmConsumer)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.ALLOWED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a user that is not in the site has no permissions on the record
.as(userName)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)); // edit record metadata capability
}
/**
* Given an incomplete inplace record
* When it is completed
* Then the inplace users still have access to the record
* And can't edit the records meta-data
*/
public void testCompletedInPlaceRecord()
{
test()
// Given an incomplete record
.given()
.as(dmCollaborator)
.perform(() -> recordService.createRecord(filePlan, dmDocument))
.expect(false)
.from(() -> recordService.isDeclared(dmDocument))
.because("Record is not complete.")
// When it is completed
.when()
.asAdmin()
.perform(() -> rmActionService.executeRecordsManagementAction(dmDocument, DeclareRecordAction.NAME))
.expect(true)
.from(() -> recordService.isDeclared(dmDocument))
.because("Record is complete.")
.then()
// Then the collaborator has filling permissions, view record capability, but not edit non-record metadata
.as(dmCollaborator)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.ALLOWED, // read record permission
AccessStatus.ALLOWED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a site contributor has read and view
.as(dmContributor)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.ALLOWED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And the consumer has read permissions and view record capability on the record
.as(dmConsumer)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.ALLOWED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a user that is not in the site has no permissions on the record
.as(userName)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)); // edit record metadata capability
}
/**
* Given an inplace record ready for destruction
* When it is destroyed
* And it's metadata is maintained
* Then the inplace users will no longer see the record
*/
public void testDestroyedRecordInplacePermissions()
{
test()
.given()
// Given that a record is declared by a collaborator
.as(dmCollaborator)
.perform(() -> recordService.createRecord(filePlan, dmDocument))
.expect(true)
.from(() -> recordService.isRecord(dmDocument))
.because("Document is a record.")
// And it is filed into the file plan
// And eligible for destruction
.asAdmin()
.perform(() ->
{
// create record category and disposition schedule
NodeRef recordCategory = filePlanService.createRecordCategory(filePlan, GUID.generate());
utils.createBasicDispositionSchedule(recordCategory, GUID.generate(), GUID.generate(), true, true);
// create record folder and file record
NodeRef recordFolder = recordFolderService.createRecordFolder(recordCategory, GUID.generate());
fileFolderService.move(dmDocument, recordFolder, null);
// cut off record
rmActionService.executeRecordsManagementAction(dmDocument, DeclareRecordAction.NAME);
utils.completeEvent(dmDocument, CommonRMTestUtils.DEFAULT_EVENT_NAME);
rmActionService.executeRecordsManagementAction(dmDocument, CutOffAction.NAME);
})
.expect("destroy")
.from(() -> dispositionService.getNextDispositionAction(dmDocument).getName())
.because("The next action is destroy.")
.expect(true)
.from(() -> dispositionService.isNextDispositionActionEligible(dmDocument))
.because("The next action is eligible.")
// When the record is destroyed
.when(() -> rmActionService.executeRecordsManagementAction(dmDocument, DestroyAction.NAME))
.then()
.expect(true)
.from(() -> recordService.isMetadataStub(dmDocument))
.because("The record has been destroyed and the meta-stub remains.")
// Then the collaborator has no permissions or capabilities
.as(dmCollaborator)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a site contributor has no permissions or capabilities
.as(dmContributor)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And the consumer has no permissions or capabilities
.as(dmConsumer)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a user that is not in the site has no permissions or capabilities
.as(userName)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)); // edit record metadata capability
}
/**
* Given an inplace record
* And the collaborator has view and edit non-record capability
* And doesn't have edit record capability
* When we add edit record metadata capability to the extended writer role
* Then the collaborator now has edit record metadata capability
*/
public void testAddUserToRole()
{
test()
.given()
.as(dmCollaborator)
// Given an inplace record
.perform(() -> recordService.createRecord(filePlan, dmDocument))
.expect(true)
.from(() -> recordService.isRecord(dmDocument))
.because("Document is a record.")
// And the collaborator has view and edit non-record capability
// And doesn't have edit record capability
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.ALLOWED, // read record permission
AccessStatus.ALLOWED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.ALLOWED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
.when()
.asAdmin()
// When we add edit record metadata capability to the extended writer role
.perform(() -> filePlanRoleService.updateRole(filePlan,
FilePlanRoleService.ROLE_EXTENDED_WRITERS,
"",
Stream
.of(viewRecordsCapability, editNonRecordMetadataCapability, editRecordMetadataCapability)
.collect(Collectors.toSet())))
.then()
.as(dmCollaborator)
// Then the collaborator now has edit record metadata capability
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.ALLOWED, // read record permission
AccessStatus.ALLOWED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.ALLOWED, // edit non record metadata capability
AccessStatus.ALLOWED)) // edit record metadata capability
;
}
/**
* Given an inplace record
* When the record is hidden
* Then the collaborator has no access to the record
* And the consumer has no access to the record
* And a user that is not in the site has no permissions or capabilities
*/
public void testNoPermissionsAfterHide()
{
test()
.given()
.as(dmCollaborator)
// Given an inplace record
.perform(() -> recordService.createRecord(filePlan, dmDocument))
.expect(true)
.from(() -> recordService.isRecord(dmDocument))
.because("Document is a record.")
.when()
.asAdmin()
// When the record is hidden
.perform(() -> inplaceRecordService.hideRecord(dmDocument))
.then()
// Then the collaborator has no access to the record
.as(dmCollaborator)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a site contributor has read and view
.as(dmContributor)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And the consumer has no access to the record
.as(dmConsumer)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a user that is not in the site has no permissions or capabilities
.as(userName)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)); // edit record metadata capability
;
}
/**
* Given an inplace record
* When the record is rejected
* Then the collaborator has no access to the record
* And the consumer has no access to the record
* And a user that is not in the site has no permissions or capabilities
*/
public void testNoPermissionsAfterReject()
{
test()
.given()
.as(dmCollaborator)
// Given an inplace record
.perform(() -> recordService.createRecord(filePlan, dmDocument))
.expect(true)
.from(() -> recordService.isRecord(dmDocument))
.because("Document is a record.")
.when()
.asAdmin()
// When the record is rejected
.perform(() -> recordService.rejectRecord(dmDocument, GUID.generate()))
.then()
// Then the collaborator has no access to the record
.as(dmCollaborator)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a site contributor has read and view
.as(dmContributor)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And the consumer has no access to the record
.as(dmConsumer)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a user that is not in the site has no permissions or capabilities
.as(userName)
.perform(() ->
checkInPlaceAccess(dmDocument,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)); // edit record metadata capability
;
}
/**
* Given a user is the cm:creator of a document
* And the user is deleted
* When the document is declared as a record by a manager
* Then it successfully becomes a record
*/
public void testCmCreatorDeletedBeforeRecordDeclaration()
{
test()
.given()
.asAdmin()
.perform(() ->
{
deletedUser = GUID.generate();
createPerson(deletedUser);
siteService.setMembership(collabSiteId, deletedUser, SiteModel.SITE_CONTRIBUTOR);
})
.as(deletedUser)
.perform(() ->
{
deleteUserDoc = fileFolderService.create(dmFolder, "deleteUserDoc.txt" , ContentModel.TYPE_CONTENT).getNodeRef();
dbNodeService.addAspect(deleteUserDoc, ContentModel.ASPECT_AUDITABLE, null);
})
.asAdmin()
.perform(() -> personService.deletePerson(deletedUser))
.when()
.as(dmCollaborator)
.perform(() -> recordService.createRecord(filePlan, deleteUserDoc))
.then()
.expect(true)
.from(() -> recordService.isRecord(deleteUserDoc))
.because("The document is now a record.")
;
}
/**
* Given a document created by the collaborator
* And declared as a record by the collaborator
* And filed by the records manager
* When the records manager copies the record
* Then the collaborator has no access to the record copy
* And a site contributor has no access to the record copy
* And the consumer has no access to the record copy
* And a user that is not in the site has no access to the record copy
*/
public void testNoPermissionsOnCopy()
{
test()
.given()
.as(dmCollaborator)
.perform(() ->
{
// Given a document created by the collaborator
copiedDoc = fileFolderService.create(dmFolder, "copiedDoc.txt" , ContentModel.TYPE_CONTENT).getNodeRef();
dbNodeService.addAspect(copiedDoc, ContentModel.ASPECT_AUDITABLE, null);
// And declared as a record by the collaborator
recordService.createRecord(filePlan, copiedDoc);
})
.asAdmin()
// And filed by the records manager
.perform(() -> fileFolderService.move(copiedDoc, rmFolder, null))
.as(dmCollaborator)
.perform(() ->
checkInPlaceAccess(copiedDoc,
AccessStatus.ALLOWED, // read record permission
AccessStatus.ALLOWED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.ALLOWED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
.when()
.asAdmin()
// When the records manager copies the record
.perform(() -> copyDoc = fileFolderService.copy(copiedDoc, rmFolder, "newRecord.txt").getNodeRef())
.then()
// Then the collaborator has no access to the record copy
.as(dmCollaborator)
.perform(() ->
checkInPlaceAccess(copyDoc,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
.perform(() ->
checkInPlaceAccess(copiedDoc,
AccessStatus.ALLOWED, // read record permission
AccessStatus.ALLOWED, // filing permission
AccessStatus.ALLOWED, // view record capability
AccessStatus.ALLOWED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a site contributor has no access to the record copy
.as(dmContributor)
.perform(() ->
checkInPlaceAccess(copyDoc,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And the consumer has no access to the record copy
.as(dmConsumer)
.perform(() ->
checkInPlaceAccess(copyDoc,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)) // edit record metadata capability
// And a user that is not in the site has no access to the record copy
.as(userName)
.perform(() ->
checkInPlaceAccess(copyDoc,
AccessStatus.DENIED, // read record permission
AccessStatus.DENIED, // filing permission
AccessStatus.DENIED, // view record capability
AccessStatus.DENIED, // edit non record metadata capability
AccessStatus.DENIED)); // edit record metadata capability
;
}
/**
* Test group reuse
*/
public void testGroupReuse()
{
test()
.when()
.as(dmCollaborator)
.perform(50, () ->
{
NodeRef newDocument = fileFolderService.create(dmFolder, GUID.generate(), ContentModel.TYPE_CONTENT).getNodeRef();
recordService.createRecord(filePlan, newDocument);
})
.as(dmContributor)
.perform(50, () ->
{
NodeRef newDocument = fileFolderService.create(dmFolder, GUID.generate(), ContentModel.TYPE_CONTENT).getNodeRef();
recordService.createRecord(filePlan, newDocument);
})
.then()
.asAdmin()
.expect(101)
.from(() -> nodeService.getChildAssocs(dmFolder).size())
.because("One hundred inplace records have been created.")
.expect(3)
.from(() -> authorityService.getContainedAuthorities(null, "GROUP_INPLACE_RECORD_MANAGEMENT", true).size())
.because("The read and write groups are reused.");
;
}
/**
* Test tear down
*/
@Override
protected void tearDownImpl()
{
super.tearDownImpl();
// clear up groups
authorityService.getContainedAuthorities(null, "GROUP_INPLACE_RECORD_MANAGEMENT", true)
.stream()
.forEach((group) -> authorityService.deleteAuthority(group));
}
}

View File

@@ -70,6 +70,9 @@ public class MoveInplaceRecordTest extends BaseRMTestCase
private Set<String> extendedReadersBeforeMove; private Set<String> extendedReadersBeforeMove;
private Set<String> extendedWritersBeforeMove; private Set<String> extendedWritersBeforeMove;
// primary parent of record
private NodeRef primaryParentBeforeMove;
public void given() public void given()
{ {
// Create the destination folder // Create the destination folder
@@ -93,8 +96,14 @@ public class MoveInplaceRecordTest extends BaseRMTestCase
// Check that the document is a record now // Check that the document is a record now
assertTrue(recordService.isRecord(dmDocument)); assertTrue(recordService.isRecord(dmDocument));
extendedReadersBeforeMove = extendedSecurityService.getExtendedReaders(dmDocument); extendedReadersBeforeMove = extendedSecurityService.getReaders(dmDocument);
extendedWritersBeforeMove = extendedSecurityService.getExtendedWriters(dmDocument); extendedWritersBeforeMove = extendedSecurityService.getWriters(dmDocument);
// get the primary parent and assert that it's a record management artifact
primaryParentBeforeMove = nodeService.getPrimaryParent(dmDocument).getParentRef();
assertTrue("Primary parent of newly created should be a records management artifact.",
filePlanService.isFilePlanComponent(primaryParentBeforeMove));
} }
public void when() public void when()
@@ -114,15 +123,27 @@ public class MoveInplaceRecordTest extends BaseRMTestCase
public void then() public void then()
{ {
// assert that the document is still a record
assertTrue("After move the document should still be a record.",
recordService.isRecord(dmDocument));
// Check that the source folder is empty now and the destination folder has the document // Check that the source folder is empty now and the destination folder has the document
assertEquals(0, nodeService.getChildAssocs(dmFolder).size()); assertEquals(0, nodeService.getChildAssocs(dmFolder).size());
List<ChildAssociationRef> destinationFolderChildAssocs = nodeService.getChildAssocs(destinationDmFolder); List<ChildAssociationRef> destinationFolderChildAssocs = nodeService.getChildAssocs(destinationDmFolder);
assertEquals(1, destinationFolderChildAssocs.size()); assertEquals(1, destinationFolderChildAssocs.size());
assertEquals(dmDocument, destinationFolderChildAssocs.get(0).getChildRef()); assertEquals(dmDocument, destinationFolderChildAssocs.get(0).getChildRef());
// Check that the primary parent of the record has remained unchanged
NodeRef primaryParentAfterMove = nodeService.getPrimaryParent(dmDocument).getParentRef();
assertTrue("Primary parent of record after inplace move should be a records management artifact.",
filePlanService.isFilePlanComponent(primaryParentAfterMove));
assertEquals("Primary parent of record after inplace move should remain the same.",
primaryParentBeforeMove,
primaryParentAfterMove);
// Check extended readers/writers // Check extended readers/writers
Set<String> extendedReadersAfterMove = extendedSecurityService.getExtendedReaders(dmDocument); Set<String> extendedReadersAfterMove = extendedSecurityService.getReaders(dmDocument);
Set<String> extendedWritersAfterMove = extendedSecurityService.getExtendedWriters(dmDocument); Set<String> extendedWritersAfterMove = extendedSecurityService.getWriters(dmDocument);
assertEquals(extendedReadersBeforeMove.size(), extendedReadersAfterMove.size()); assertEquals(extendedReadersBeforeMove.size(), extendedReadersAfterMove.size());
assertEquals(extendedWritersBeforeMove.size(), extendedWritersAfterMove.size()); assertEquals(extendedWritersBeforeMove.size(), extendedWritersAfterMove.size());

View File

@@ -30,6 +30,7 @@ package org.alfresco.module.org_alfresco_module_rm.test.legacy.action;
import org.alfresco.module.org_alfresco_module_rm.action.impl.FileReportAction; import org.alfresco.module.org_alfresco_module_rm.action.impl.FileReportAction;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@@ -62,6 +63,8 @@ public class FileReportActionTest extends BaseRMTestCase
private void fileReport(final String mimeType) private void fileReport(final String mimeType)
{ {
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
// create record folder // create record folder
final NodeRef recordFolder = recordFolderService.createRecordFolder(rmContainer, GUID.generate()); final NodeRef recordFolder = recordFolderService.createRecordFolder(rmContainer, GUID.generate());

View File

@@ -119,24 +119,27 @@ public class FileToActionTest extends BaseRMTestCase
// create record from document // create record from document
recordService.createRecord(filePlan, dmDocument); recordService.createRecord(filePlan, dmDocument);
return null;
}
@Override
public void test(Void result) throws Exception
{
AuthenticationUtil.runAs(() ->
{
// check things have gone according to plan // check things have gone according to plan
assertTrue(recordService.isRecord(dmDocument)); assertTrue(recordService.isRecord(dmDocument));
assertFalse(recordService.isFiled(dmDocument)); assertFalse(recordService.isFiled(dmDocument));
AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Void>()
{
public Void doWork() throws Exception
{
// is the unfiled container the primary parent of the filed record // is the unfiled container the primary parent of the filed record
NodeRef parent = nodeService.getPrimaryParent(dmDocument).getParentRef(); NodeRef parent = nodeService.getPrimaryParent(dmDocument).getParentRef();
assertEquals(filePlanService.getUnfiledContainer(filePlan), parent); assertEquals(filePlanService.getUnfiledContainer(filePlan), parent);
// TODO Auto-generated method stub
return null;
}});
return null; return null;
},
AuthenticationUtil.getAdminUserName());
} }
}, dmCollaborator); }, dmCollaborator);
} }

View File

@@ -113,7 +113,8 @@ public class RejectActionTest extends BaseRMTestCase
assertTrue(nodeService.getParentAssocs(dmDocument).size() == 1); assertTrue(nodeService.getParentAssocs(dmDocument).size() == 1);
// The extended reader information should be removed // The extended reader information should be removed
assertNull(extendedSecurityService.getExtendedReaders(dmDocument)); assertFalse(extendedSecurityService.hasExtendedSecurity(dmDocument));
assertTrue(extendedSecurityService.getReaders(dmDocument).isEmpty());
return null; return null;
} }

View File

@@ -27,9 +27,7 @@
package org.alfresco.module.org_alfresco_module_rm.test.legacy.service; package org.alfresco.module.org_alfresco_module_rm.test.legacy.service;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
@@ -101,64 +99,29 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
assertFalse(extendedSecurityService.hasExtendedSecurity(rmFolder)); assertFalse(extendedSecurityService.hasExtendedSecurity(rmFolder));
assertFalse(extendedSecurityService.hasExtendedSecurity(record)); assertFalse(extendedSecurityService.hasExtendedSecurity(record));
assertNull(extendedSecurityService.getExtendedReaders(record)); assertTrue(extendedSecurityService.getReaders(record).isEmpty());
assertNull(extendedSecurityService.getExtendedWriters(record)); assertTrue(extendedSecurityService.getWriters(record).isEmpty());
Set<String> extendedReaders = new HashSet<String>(2); Set<String> extendedReaders = new HashSet<String>(2);
extendedReaders.add(monkey); extendedReaders.add(monkey);
extendedReaders.add(elephant); extendedReaders.add(elephant);
extendedSecurityService.addExtendedSecurity(record, extendedReaders, null); extendedSecurityService.set(record, extendedReaders, null);
checkExtendedReaders(record, extendedReaders);
Map<String, Integer> testMap = new HashMap<String, Integer>(2);
testMap.put(monkey, Integer.valueOf(1));
testMap.put(elephant, Integer.valueOf(1));
checkExtendedReaders(record, testMap);
Set<String> extendedReadersToo = new HashSet<String>(2); Set<String> extendedReadersToo = new HashSet<String>(2);
extendedReadersToo.add(monkey); extendedReadersToo.add(monkey);
extendedReadersToo.add(snake); extendedReadersToo.add(snake);
extendedSecurityService.addExtendedSecurity(recordToo, extendedReadersToo, null); extendedSecurityService.set(recordToo, extendedReadersToo, null);
checkExtendedReaders(recordToo, extendedReadersToo);
Map<String, Integer> testMapToo = new HashMap<String, Integer>(2); // test remove
testMapToo.put(monkey, Integer.valueOf(1)); extendedSecurityService.remove(recordToo);
testMapToo.put(snake, Integer.valueOf(1));
Map<String, Integer> testMapThree = new HashMap<String, Integer>(3); assertFalse(extendedSecurityService.hasExtendedSecurity(recordToo));
testMapThree.put(monkey, Integer.valueOf(2)); assertTrue(extendedSecurityService.getReaders(recordToo).isEmpty());
testMapThree.put(elephant, Integer.valueOf(1)); assertTrue(extendedSecurityService.getWriters(recordToo).isEmpty());
testMapThree.put(snake, Integer.valueOf(1));
checkExtendedReaders(recordToo, testMapToo);
// test remove (with no parent inheritance)
Set<String> removeMap1 = new HashSet<String>(2);
removeMap1.add(elephant);
removeMap1.add(monkey);
extendedSecurityService.removeExtendedSecurity(rmFolder, removeMap1, null, false);
Map<String, Integer> testMapFour = new HashMap<String, Integer>(2);
testMapFour.put(monkey, Integer.valueOf(1));
testMapFour.put(snake, Integer.valueOf(1));
checkExtendedReaders(recordToo, testMapToo);
// test remove (apply to parents)
Set<String> removeMap2 = new HashSet<String>(1);
removeMap2.add(snake);
extendedSecurityService.removeExtendedSecurity(recordToo, removeMap2, null, true);
testMapThree.remove(snake);
testMapFour.remove(snake);
testMapToo.remove(snake);
checkExtendedReaders(recordToo, testMapToo);
return null; return null;
} }
@@ -172,12 +135,12 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
doTestInTransaction(new Test<Void>() doTestInTransaction(new Test<Void>()
{ {
Map<String, Integer> testMap = new HashMap<String, Integer>(2); Set<String> extendedReaders = new HashSet<String>(2);;
public Void run() throws Exception public Void run() throws Exception
{ {
testMap.put(monkey, Integer.valueOf(1)); extendedReaders.add(monkey);
testMap.put(elephant, Integer.valueOf(1)); extendedReaders.add(elephant);
assertFalse(extendedSecurityService.hasExtendedSecurity(filePlan)); assertFalse(extendedSecurityService.hasExtendedSecurity(filePlan));
assertFalse(extendedSecurityService.hasExtendedSecurity(rmContainer)); assertFalse(extendedSecurityService.hasExtendedSecurity(rmContainer));
@@ -186,15 +149,12 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordCategory)); assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordCategory));
assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordFolder)); assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordFolder));
assertNull(extendedSecurityService.getExtendedReaders(record)); assertTrue(extendedSecurityService.getReaders(record).isEmpty());
Set<String> extendedReaders = new HashSet<String>(2); extendedSecurityService.set(record, extendedReaders, null);
extendedReaders.add(monkey);
extendedReaders.add(elephant);
extendedSecurityService.addExtendedSecurity(record, extendedReaders, null); checkExtendedReaders(record, extendedReaders);
checkExtendedReaders(record, testMap);
assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordCategory)); assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordCategory));
assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordFolder)); assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordFolder));
@@ -206,31 +166,21 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
@Override @Override
public void test(Void result) throws Exception public void test(Void result) throws Exception
{ {
checkExtendedReaders(record, testMap); checkExtendedReaders(record, extendedReaders);
} }
}); });
} }
/**
@SuppressWarnings("unchecked") * Check extended readers helper method
private void checkExtendedReaders(NodeRef nodeRef, Map<String, Integer> testMap) */
private void checkExtendedReaders(NodeRef nodeRef, Set<String> testReaders)
{ {
assertTrue(extendedSecurityService.hasExtendedSecurity(nodeRef)); assertTrue(extendedSecurityService.hasExtendedSecurity(nodeRef));
Map<String, Integer> readersMap = (Map<String,Integer>)nodeService.getProperty(nodeRef, PROP_READERS); Set<String> readers = extendedSecurityService.getReaders(nodeRef);
assertNotNull(readersMap);
assertEquals(testMap.size(), readersMap.size());
for (Map.Entry<String, Integer> entry: testMap.entrySet())
{
assertTrue(readersMap.containsKey(entry.getKey()));
assertEquals(entry.getKey(), entry.getValue(), readersMap.get(entry.getKey()));
}
Set<String> readers = extendedSecurityService.getExtendedReaders(nodeRef);
assertNotNull(readers); assertNotNull(readers);
assertEquals(testMap.size(), readers.size()); assertEquals(testReaders, readers);
} }
public void testDifferentUsersDifferentPermissions() public void testDifferentUsersDifferentPermissions()

View File

@@ -33,8 +33,6 @@ import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService; import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -1241,10 +1239,6 @@ public class FilePlanPermissionServiceImplTest extends BaseRMTestCase
accessPermissions.put(permission.getAuthority(), permission.getPermission()); accessPermissions.put(permission.getAuthority(), permission.getPermission());
} }
assertTrue(accessPermissions.containsKey(ExtendedReaderDynamicAuthority.EXTENDED_READER));
assertEquals(RMPermissionModel.READ_RECORDS, accessPermissions.get(ExtendedReaderDynamicAuthority.EXTENDED_READER));
assertTrue(accessPermissions.containsKey(ExtendedWriterDynamicAuthority.EXTENDED_WRITER));
assertEquals(RMPermissionModel.FILING, accessPermissions.get(ExtendedWriterDynamicAuthority.EXTENDED_WRITER));
String adminRole = authorityService.getName(AuthorityType.GROUP, FilePlanRoleService.ROLE_ADMIN + filePlan.getId()); String adminRole = authorityService.getName(AuthorityType.GROUP, FilePlanRoleService.ROLE_ADMIN + filePlan.getId());
assertTrue(accessPermissions.containsKey(adminRole)); assertTrue(accessPermissions.containsKey(adminRole));
assertEquals(RMPermissionModel.FILING, accessPermissions.get(adminRole)); assertEquals(RMPermissionModel.FILING, accessPermissions.get(adminRole));

View File

@@ -38,8 +38,6 @@ import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.role.Role; import org.alfresco.module.org_alfresco_module_rm.role.Role;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
@@ -181,22 +179,13 @@ public class RecordServiceImplTest extends BaseRMTestCase
public void testExtendedWriters() throws Exception public void testExtendedWriters() throws Exception
{ {
final ExtendedReaderDynamicAuthority readerDy = (ExtendedReaderDynamicAuthority)applicationContext.getBean("extendedReaderDynamicAuthority");
final ExtendedWriterDynamicAuthority writerDy = (ExtendedWriterDynamicAuthority)applicationContext.getBean("extendedWriterDynamicAuthority");
doTestInTransaction(new Test<Void>() doTestInTransaction(new Test<Void>()
{ {
@Override @Override
public Void run() public Void run()
{ {
assertNull(extendedSecurityService.getExtendedReaders(recordOne)); assertTrue(extendedSecurityService.getReaders(recordOne).isEmpty());
assertNull(extendedSecurityService.getExtendedWriters(recordOne)); assertTrue(extendedSecurityService.getWriters(recordOne).isEmpty());
assertFalse(readerDy.hasAuthority(recordOne, dmCollaborator));
assertFalse(writerDy.hasAuthority(recordOne, dmCollaborator));
assertFalse(readerDy.hasAuthority(filePlan, dmCollaborator));
assertFalse(writerDy.hasAuthority(filePlan, dmCollaborator));
return null; return null;
} }
@@ -209,16 +198,9 @@ public class RecordServiceImplTest extends BaseRMTestCase
{ {
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(recordOne, RMPermissionModel.READ_RECORDS)); assertEquals(AccessStatus.DENIED, permissionService.hasPermission(recordOne, RMPermissionModel.READ_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(recordOne, RMPermissionModel.FILING)); assertEquals(AccessStatus.DENIED, permissionService.hasPermission(recordOne, RMPermissionModel.FILING));
assertFalse(readerDy.hasAuthority(recordOne, dmCollaborator));
assertFalse(writerDy.hasAuthority(recordOne, dmCollaborator));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS)); assertEquals(AccessStatus.DENIED, permissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(filePlan, RMPermissionModel.EDIT_NON_RECORD_METADATA)); assertEquals(AccessStatus.DENIED, permissionService.hasPermission(filePlan, RMPermissionModel.EDIT_NON_RECORD_METADATA));
assertFalse(readerDy.hasAuthority(filePlan, dmCollaborator));
assertFalse(writerDy.hasAuthority(filePlan, dmCollaborator));
return null; return null;
} }
}, dmCollaborator); }, dmCollaborator);
@@ -230,10 +212,10 @@ public class RecordServiceImplTest extends BaseRMTestCase
{ {
Set<String> writers = new HashSet<String>(1); Set<String> writers = new HashSet<String>(1);
writers.add(dmCollaborator); writers.add(dmCollaborator);
extendedSecurityService.addExtendedSecurity(recordOne, null, writers); extendedSecurityService.set(recordOne, null, writers);
assertNull(extendedSecurityService.getExtendedReaders(recordOne)); assertTrue(extendedSecurityService.getReaders(recordOne).isEmpty());
assertFalse(extendedSecurityService.getExtendedWriters(recordOne).isEmpty()); assertFalse(extendedSecurityService.getWriters(recordOne).isEmpty());
return null; return null;
} }
@@ -247,9 +229,7 @@ public class RecordServiceImplTest extends BaseRMTestCase
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(recordOne, RMPermissionModel.READ_RECORDS)); assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(recordOne, RMPermissionModel.READ_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(recordOne, RMPermissionModel.FILING)); assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(recordOne, RMPermissionModel.FILING));
assertFalse(readerDy.hasAuthority(recordOne, dmCollaborator)); // ALLOWED, becuase users have been added to the in-place roles
assertTrue(writerDy.hasAuthority(recordOne, dmCollaborator));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS)); assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan, RMPermissionModel.EDIT_NON_RECORD_METADATA)); assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan, RMPermissionModel.EDIT_NON_RECORD_METADATA));
@@ -311,7 +291,8 @@ public class RecordServiceImplTest extends BaseRMTestCase
public void test(Void result) public void test(Void result)
{ {
checkPermissions(READ_RECORDS, AccessStatus.DENIED, // file plan checkPermissions(READ_RECORDS,
AccessStatus.DENIED, // file plan
AccessStatus.DENIED, // unfiled container AccessStatus.DENIED, // unfiled container
AccessStatus.DENIED, // record category AccessStatus.DENIED, // record category
AccessStatus.DENIED, // record folder AccessStatus.DENIED, // record folder
@@ -320,7 +301,8 @@ public class RecordServiceImplTest extends BaseRMTestCase
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan, assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan,
RMPermissionModel.VIEW_RECORDS)); RMPermissionModel.VIEW_RECORDS));
checkPermissions(FILING, AccessStatus.DENIED, // file plan checkPermissions(FILING,
AccessStatus.DENIED, // file plan
AccessStatus.DENIED, // unfiled container AccessStatus.DENIED, // unfiled container
AccessStatus.DENIED, // record category AccessStatus.DENIED, // record category
AccessStatus.DENIED, // record folder AccessStatus.DENIED, // record folder

View File

@@ -423,11 +423,12 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase
@Override @Override
public Object execute() throws Throwable public Object execute() throws Throwable
{ {
// As system user
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
// Do the tear down // Do the tear down
AuthenticationUtil.runAsSystem(() ->
{
tearDownImpl(); tearDownImpl();
return null;
});
return null; return null;
} }
@@ -601,17 +602,22 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase
} }
protected void setupTestUsers(final NodeRef filePlan) protected void setupTestUsers(final NodeRef filePlan)
{
AuthenticationUtil.runAs(() ->
{ {
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>() retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{ {
@Override @Override
public Object execute() throws Throwable public Object execute() throws Throwable
{ {
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
setupTestUsersImpl(filePlan); setupTestUsersImpl(filePlan);
return null; return null;
} }
}); });
return null;
},
AuthenticationUtil.getAdminUserName());
} }
/** /**
@@ -687,19 +693,15 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase
*/ */
protected void setupMultiHierarchyTestData() protected void setupMultiHierarchyTestData()
{ {
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>() AuthenticationUtil.runAsSystem(() ->
{ {
@Override return retryingTransactionHelper.doInTransaction(() ->
public Object execute() throws Throwable
{ {
// As system user
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
// Do setup // Do setup
setupMultiHierarchyTestDataImpl(); setupMultiHierarchyTestDataImpl();
return null; return null;
} });
}); });
} }

View File

@@ -0,0 +1,276 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.test.util.bdt;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
/**
* Helper class that provides an simple way to write behaviour integration tests.
* <p>
* Note that initBehaviourTest() must be called before given() is called.
*
* @author Roy Wetherall
* @since 2.5
*/
public class BehaviourTest
{
/** retrying transaction helper */
private static RetryingTransactionHelper retryingTransactionHelper;
/** current execution user */
private String asUser = AuthenticationUtil.getAdminUserName();
/**
* Initialise behaviour tests for execution with retrying transaction helper
*
* @param retryingTransactionHelper retrying transaction helper
*/
public static void initBehaviourTests(RetryingTransactionHelper retryingTransactionHelper)
{
BehaviourTest.retryingTransactionHelper = retryingTransactionHelper;
}
/**
* Start a test
*
* @return BehaviourTest new test instance
*/
public static BehaviourTest test()
{
return new BehaviourTest();
}
/**
* Helper method to get the retrying transaction helper
*
* @return RetryingTransactionHelper retrying transaction helper
*/
/*package*/ RetryingTransactionHelper getRetryingTransactionHelper()
{
return retryingTransactionHelper;
}
/**
* Helper method to get the execution user
*
* @return String execution user
*/
/* package*/ String getAsUser()
{
return asUser;
}
/**
* Helper method to switch the current execution user to admin.
*
* @return BehaviourTest test instance
*/
public BehaviourTest asAdmin()
{
return as(AuthenticationUtil.getAdminUserName());
}
/**
* Set execution user
*
* @param asUser execution user
* @return BehaviourTest test instance
*/
public BehaviourTest as(String asUser)
{
this.asUser = asUser;
return this;
}
/**
* Given.
* <p>
* Used to group together given conditions.
*
* @return BehaviourTest test instance
*/
public BehaviourTest given()
{
return this;
}
/**
* Given.
* <p>
* Performs work.
*
* @param given work to do
* @return BehaviourTest test instance
*/
public BehaviourTest given(Work given)
{
return perform(given);
}
/**
* When.
* <p>
* Used to group together when actions.
*
* @return BehaviourTest test instance
*/
public BehaviourTest when()
{
return this;
}
/**
* When.
* <p>
* Performs work.
*
* @param when work to do
* @return BehaviourTest test instance
*/
public BehaviourTest when(Work when)
{
return perform(when);
}
/**
* Then.
* <p>
* Used to group together then actions.
*
* @return BehaviourTest test instance
*/
public BehaviourTest then()
{
return this;
}
/**
* Then.
* <p>
* Performs work.
*
* @param then work to do
* @return BehaviourTest test instance
*/
public BehaviourTest then(Work then)
{
return perform(then);
}
/**
* Expect a value.
*
* @param value value
* @return ExpectedValue expected value evaluator
*/
public ExpectedValue<Boolean> expect(boolean value)
{
return new ExpectedValue<Boolean>(this, value);
}
/**
* Expect a value.
*
* @param value value
* @return ExpectedValue expected value evaluator
*/
public ExpectedValue<String> expect(String value)
{
return new ExpectedValue<String>(this, value);
}
/**
* Expect a value.
*
* @param value value
* @return ExpectedValue expected value evaluator
*/
public ExpectedValue<Object> expect(Object value)
{
return new ExpectedValue<Object>(this, value);
}
/**
* Expect a failure.
*
* @param exceptionClass expected exception
* @return ExpectedFailure expected failure evaluator
*/
public ExpectedFailure expectException(Class<? extends Exception> exceptionClass)
{
return new ExpectedFailure(this, exceptionClass);
}
/**
* Perform work a number of times
*
* @param count number of times to perform the work
* @param work work to perform
* @return BehaviourTest test instance
*/
public BehaviourTest perform(int count, Work work)
{
for (int i = 0; i < count; i++)
{
perform(work);
}
return this;
}
/**
* Perform work
*
* @param work work to perform
* @return BehaviourTest test instance
*/
public BehaviourTest perform(Work work)
{
return AuthenticationUtil.runAs(() ->
{
return retryingTransactionHelper.doInTransaction(() ->
{
work.doIt();
return this;
});
},
this.asUser);
}
/**
* Work Interface
*/
public interface Work
{
/**
* Do the work.
*/
void doIt() throws Exception;
}
}

View File

@@ -0,0 +1,92 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.test.util.bdt;
import static org.junit.Assert.fail;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import org.alfresco.module.org_alfresco_module_rm.test.util.bdt.BehaviourTest.Work;
/**
* Expected failure.
*
* @author Roy Wetherall
* @since 2.5
*/
public class ExpectedFailure
{
private static final String MESSAGE = "Expected failure \"{0}\" was not observed.";
private BehaviourTest test;
private Set<Class<? extends Exception>> exceptionClasses;
private Work work;
@SafeVarargs
public ExpectedFailure(BehaviourTest test, Class<? extends Exception> ...exceptionClasses)
{
this.test = test;
this.exceptionClasses = Arrays.stream(exceptionClasses).collect(Collectors.toSet());
}
public ExpectedFailure from(Work work)
{
this.work = work;
return this;
}
public BehaviourTest because(String message)
{
try
{
test.perform(work);
}
catch(Exception actualException)
{
boolean found = false;
for (Class<? extends Exception> exceptionClass : exceptionClasses)
{
if (exceptionClass.isAssignableFrom(actualException.getClass()))
{
found = true;
}
}
if (!found)
{
fail(MessageFormat.format(MESSAGE, message));
}
}
return test;
}
}

View File

@@ -0,0 +1,86 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.test.util.bdt;
import static org.junit.Assert.assertEquals;
import java.text.MessageFormat;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
/**
* Expected value.
*
* @author Roy Wetherall
* @since 2.5
*/
public class ExpectedValue<T>
{
private static final String MESSAGE = "Expected value outcome \"{0}\" was not observed.";
private T expectedValue;
private Evaluation<T> evaluation;
private BehaviourTest test;
public ExpectedValue(BehaviourTest test, T value)
{
this.expectedValue = value;
this.test = test;
}
public ExpectedValue<T> from(Evaluation<T> evaluation)
{
this.evaluation = evaluation;
return this;
}
public BehaviourTest because(String message)
{
T actualValue = (T)AuthenticationUtil.runAs(() ->
{
return test.getRetryingTransactionHelper().doInTransaction(() ->
{
return evaluation.eval();
});
},
test.getAsUser());
if (message != null)
{
message = MessageFormat.format(MESSAGE, message);
}
assertEquals(message, expectedValue, actualValue);
return test;
}
public interface Evaluation<T>
{
T eval() throws Exception;
}
}

View File

@@ -0,0 +1,928 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.security;
import static org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityServiceImpl.READER_GROUP_PREFIX;
import static org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityServiceImpl.ROOT_IPR_GROUP;
import static org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityServiceImpl.WRITER_GROUP_PREFIX;
import static org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock.generateText;
import static org.alfresco.service.cmr.security.PermissionService.GROUP_PREFIX;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anySet;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.alfresco.model.RenditionModel;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.security.authority.RMAuthority;
import org.alfresco.repo.security.permissions.impl.AccessPermissionImpl;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
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.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
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.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
/**
* Extended security service implementation unit test.
*
* @author Roy Wetherall
* @since 2.5
*/
public class ExtendedSecurityServiceImplUnitTest
{
/** service mocks*/
@Mock private FilePlanService mockedFilePlanService;
@Mock private FilePlanRoleService mockedFilePlanRoleService;
@Mock private AuthorityService mockedAuthorityService;
@Mock private PermissionService mockedPermissionService;
@Mock private TransactionService mockedTransactionService;
@Mock private RetryingTransactionHelper mockedRetryingTransactionHelper;
@Mock private NodeService mockedNodeService;
@Mock private PagingResults<String> mockedReadPagingResults;
@Mock private PagingResults<String> mockedWritePagingResults;
@Mock private ApplicationContext mockedApplicationContext;
@Mock private ChildAssociationRef mockedChildAssociationRef;
/** test component */
@InjectMocks private ExtendedSecurityServiceImpl extendedSecurityService;
/** read/write group full names */
private static final String READER_GROUP_FULL_PREFIX = GROUP_PREFIX + READER_GROUP_PREFIX;
private static final String WRITER_GROUP_FULL_PREFIX = GROUP_PREFIX + WRITER_GROUP_PREFIX;
/** test authorities */
private static final String USER = "USER";
private static final String GROUP = GROUP_PREFIX + "GROUP";
private static final String USER_W = "USER_W";
private static final String GROUP_W = GROUP_PREFIX + "GROUP_W";
private static final Set<String> READERS = Stream.of(USER, GROUP).collect(Collectors.toSet());
private static final Set<String> WRITERS = Stream.of(USER_W, GROUP_W).collect(Collectors.toSet());
/** has extended security permission set */
private static final Set<AccessPermission> HAS_EXTENDED_SECURITY = Stream
.of(new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, READER_GROUP_FULL_PREFIX, 0),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, AlfMock.generateText(), 1),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, WRITER_GROUP_FULL_PREFIX, 2))
.collect(Collectors.toSet());
/** has no extended security permission set */
private static final Set<AccessPermission> HAS_NO_EXTENDED_SECURITY = Stream
.of(new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, AlfMock.generateText(), 0),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, AlfMock.generateText(), 1),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, AlfMock.generateText(), 2))
.collect(Collectors.toSet());
/** test data */
private NodeRef nodeRef;
private NodeRef filePlan;
private String readGroupPrefix;
private String writeGroupPrefix;
/**
* Before tests
*/
@SuppressWarnings("unchecked")
@Before public void before()
{
// initialise mocks
MockitoAnnotations.initMocks(this);
// setup node
nodeRef = AlfMock.generateNodeRef(mockedNodeService);
// setup file plan
filePlan = AlfMock.generateNodeRef(mockedNodeService);
when(mockedFilePlanService.getFilePlan(any(NodeRef.class)))
.thenReturn(filePlan);
// set-up application context
when(mockedApplicationContext.getBean("dbNodeService"))
.thenReturn(mockedNodeService);
// setup retrying transaction helper
Answer<Object> doInTransactionAnswer = new Answer<Object>()
{
@SuppressWarnings("rawtypes")
@Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
RetryingTransactionCallback callback = (RetryingTransactionCallback)invocation.getArguments()[0];
return callback.execute();
}
};
doAnswer(doInTransactionAnswer)
.when(mockedRetryingTransactionHelper)
.<Object>doInTransaction(any(RetryingTransactionCallback.class));
when(mockedTransactionService.getRetryingTransactionHelper())
.thenReturn(mockedRetryingTransactionHelper);
// setup create authority
Answer<String> createAuthorityAnswer = new Answer<String>()
{
public String answer(InvocationOnMock invocation) throws Throwable
{
return PermissionService.GROUP_PREFIX + (String)invocation.getArguments()[1];
}
};
when(mockedAuthorityService.createAuthority(any(AuthorityType.class), anyString(), anyString(), anySet()))
.thenAnswer(createAuthorityAnswer);
// setup group prefixes
readGroupPrefix = extendedSecurityService.getIPRGroupPrefixShortName(READER_GROUP_PREFIX, READERS);
writeGroupPrefix = extendedSecurityService.getIPRGroupPrefixShortName(WRITER_GROUP_PREFIX, WRITERS);
// make sure the users and groups exist
Stream
.of(USER, USER_W, GROUP, GROUP_W)
.forEach((a) ->
when(mockedAuthorityService.authorityExists(a))
.thenReturn(true));
}
/**
* Given that the root authority does not exist
* When the application context is refreshed
* Then the root authority is created
*/
@Test public void rootAuthorityDoesNotExist()
{
// group doesn't exist
when(mockedAuthorityService.authorityExists(GROUP_PREFIX + ExtendedSecurityServiceImpl.ROOT_IPR_GROUP))
.thenReturn(false);
// refresh context
extendedSecurityService.onApplicationEvent(mock(ContextRefreshedEvent.class));
// verify group is created
verify(mockedAuthorityService).createAuthority(AuthorityType.GROUP, ROOT_IPR_GROUP, ROOT_IPR_GROUP, Collections.singleton(RMAuthority.ZONE_APP_RM));
}
/**
* Given that the root authority exists
* When the application context is refreshed
* Then nothing happens
*/
@Test public void rootAuthorityDoesExist()
{
// group doesn't exist
when(mockedAuthorityService.authorityExists(GROUP_PREFIX + ROOT_IPR_GROUP))
.thenReturn(true);
// refresh context
extendedSecurityService.onApplicationEvent(mock(ContextRefreshedEvent.class));
// verify group is created
verify(mockedAuthorityService, never()).createAuthority(AuthorityType.GROUP, ROOT_IPR_GROUP, ROOT_IPR_GROUP, Collections.singleton(RMAuthority.ZONE_APP_RM));
}
/**
* Given that an IPR read group has read on a node
* And that an IPR write group has filling on a node
* When checking for the existence of extended permissions on that node
* Then it will be confirmed
*/
@Test public void hasExtendedSecurityWithReadAndWriteGroups()
{
// setup permissions
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(HAS_EXTENDED_SECURITY);
// has extended security
assertTrue(extendedSecurityService.hasExtendedSecurity(nodeRef));
}
/**
* Given that there is no IPR read group has read on a node
* When checking for the existence of extended permissions on that node
* Then it will be denied
*/
@Test public void hasExtendedSecurityWithNoReadGroup()
{
// setup permissions
Set<AccessPermission> permissions = Stream
.of(new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, AlfMock.generateText(), 0),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, AlfMock.generateText(), 1),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, GROUP_PREFIX + WRITER_GROUP_PREFIX, 2))
.collect(Collectors.toSet());
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(permissions);
// has extended security
assertFalse(extendedSecurityService.hasExtendedSecurity(nodeRef));
}
/**
* Given that there is no IPR write group has read on a node
* When checking for the existence of extended permissions on that node
* Then it will be denied
*/
@Test public void hasExtendedSecurityWithNoWriteGroup()
{
// setup permissions
Set<AccessPermission> permissions = Stream
.of(new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, GROUP_PREFIX + READER_GROUP_PREFIX, 0),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, AlfMock.generateText(), 1),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, AlfMock.generateText(), 2))
.collect(Collectors.toSet());
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(permissions);
// has extended security
assertFalse(extendedSecurityService.hasExtendedSecurity(nodeRef));
}
/**
* Given that an IPR read group has no groups assigned permission
* When checking for the existence of extended permissions on that node
* Then it will be denied
*/
@Test public void hasExtendedSecurityWithNoAssignedGroups()
{
// setup permissions
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(HAS_NO_EXTENDED_SECURITY);
// has extended security
assertFalse(extendedSecurityService.hasExtendedSecurity(nodeRef));
}
/**
* Given that there are no IPR groups assigned
* When I try and get the extended readers
* The I will get an empty set
*/
@Test public void getExtendedReadersNoIPRGroupsAssigned()
{
// setup permissions
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(HAS_NO_EXTENDED_SECURITY);
// get extended readers
assertTrue(extendedSecurityService.getReaders(nodeRef).isEmpty());
}
/**
* Given that there are IPR groups assigned
* When I try and get the extended readers
* The I will get the set of readers
*/
@Test public void getExtendedReaders()
{
// setup permissions
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(HAS_EXTENDED_SECURITY);
when(mockedAuthorityService.getContainedAuthorities(null, READER_GROUP_FULL_PREFIX, true))
.thenReturn(Stream
.of(USER, GROUP)
.collect(Collectors.toSet()));
// get extended readers
Set<String> extendedReaders = extendedSecurityService.getReaders(nodeRef);
assertEquals(Stream
.of(USER, GROUP)
.collect(Collectors.toSet()),
extendedReaders);
}
/**
* Given that there are no IPR groups assigned
* When I try and get the extended writers
* The I will get an empty set
*/
@Test public void getExtendedWritersNoIPRGroupsAssigned()
{
// setup permissions
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(HAS_NO_EXTENDED_SECURITY);
// get extended writers
assertTrue(extendedSecurityService.getWriters(nodeRef).isEmpty());
}
/**
* Given that there are IPR groups assigned
* When I try and get the extended writers
* The I will get the set of writers
*/
@Test public void getExtendedWriters()
{
// setup permissions
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(HAS_EXTENDED_SECURITY);
when(mockedAuthorityService.getContainedAuthorities(null, WRITER_GROUP_FULL_PREFIX, true))
.thenReturn(Stream
.of(USER, GROUP)
.collect(Collectors.toSet()));
// get extended writers
Set<String> extendedWriters = extendedSecurityService.getWriters(nodeRef);
assertEquals(Stream
.of(USER, GROUP)
.collect(Collectors.toSet()),
extendedWriters);
}
/**
* Given a node with no previous IPR groups assigned
* And no IPR group matching authorities
* When I add some read and write authorities
* Then new IPR groups are created
* And they are assigned to the node
* And they are added to the RM roles
*/
@Test public void addExtendedSecurityForTheFirstTimeAndCreateGroups()
{
// group names
String readGroup = extendedSecurityService.getIPRGroupShortName(READER_GROUP_PREFIX, READERS, 0);
String writeGroup = extendedSecurityService.getIPRGroupShortName(WRITER_GROUP_PREFIX, WRITERS, 0);
// setup query results
when(mockedReadPagingResults.getPage())
.thenReturn(Collections.emptyList());
when(mockedAuthorityService.getAuthorities(
eq(AuthorityType.GROUP),
eq(RMAuthority.ZONE_APP_RM),
any(String.class),
eq(false),
eq(false),
any(PagingRequest.class)))
.thenReturn(mockedReadPagingResults);
// add extended security
extendedSecurityService.set(nodeRef, READERS, WRITERS);
// verify no old permissions needing to be cleared
verify(mockedPermissionService, never()).clearPermission(eq(nodeRef), anyString());
// verify read group created correctly
verify(mockedAuthorityService).createAuthority(AuthorityType.GROUP, readGroup, readGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
readGroup = GROUP_PREFIX + readGroup;
verify(mockedAuthorityService).addAuthority(GROUP_PREFIX + ROOT_IPR_GROUP, readGroup);
verify(mockedAuthorityService).addAuthority(readGroup, USER);
verify(mockedAuthorityService).addAuthority(readGroup, GROUP);
// verify write group created correctly
verify(mockedAuthorityService).createAuthority(AuthorityType.GROUP, writeGroup, writeGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
writeGroup = GROUP_PREFIX + writeGroup;
verify(mockedAuthorityService).addAuthority(GROUP_PREFIX + ROOT_IPR_GROUP, writeGroup);
verify(mockedAuthorityService).addAuthority(writeGroup, USER_W);
verify(mockedAuthorityService).addAuthority(writeGroup, GROUP_W);
// verify groups assigned to RM roles
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_READERS, readGroup);
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_WRITERS, writeGroup);
// verify permissions are assigned to node
verify(mockedPermissionService).setPermission(nodeRef, readGroup, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService).setPermission(nodeRef, writeGroup, RMPermissionModel.FILING, true);
}
/**
* Given a node with no previous IPR groups assigned
* And existing IPR groups matching
* When I add some read and write authorities
* Then the existing IPR groups are used
* And they are assigned to the node
* And do not not need to be re-added to the RM roles
*/
@Test public void addExtendedSecurityForTheFirstTimeAndReuseGroups()
{
// group names
String readGroup = readGroupPrefix + "0";
String writeGroup = writeGroupPrefix + "0";
// setup query results
when(mockedReadPagingResults.getPage())
.thenReturn(Stream.of(GROUP_PREFIX + readGroup).collect(Collectors.toList()));
when(mockedAuthorityService.getAuthorities(
eq(AuthorityType.GROUP),
eq(RMAuthority.ZONE_APP_RM),
eq(readGroupPrefix),
eq(false),
eq(false),
any(PagingRequest.class)))
.thenReturn(mockedReadPagingResults);
when(mockedWritePagingResults.getPage())
.thenReturn(Stream.of(GROUP_PREFIX + writeGroup).collect(Collectors.toList()));
when(mockedAuthorityService.getAuthorities(
eq(AuthorityType.GROUP),
eq(RMAuthority.ZONE_APP_RM),
eq(writeGroupPrefix),
eq(false),
eq(false),
any(PagingRequest.class)))
.thenReturn(mockedWritePagingResults);
// setup exact match
when(mockedAuthorityService.authorityExists(GROUP_PREFIX + writeGroup))
.thenReturn(true);
when(mockedAuthorityService.getContainedAuthorities(null, GROUP_PREFIX + readGroup, true))
.thenReturn(Stream
.of(USER, GROUP)
.collect(Collectors.toSet()));
when(mockedAuthorityService.getContainedAuthorities(null, GROUP_PREFIX + writeGroup, true))
.thenReturn(Stream
.of(USER_W, GROUP_W)
.collect(Collectors.toSet()));
// add extended security
extendedSecurityService.set(nodeRef, READERS, WRITERS);
// verify no old permissions needing to be cleared
verify(mockedPermissionService, never()).clearPermission(eq(nodeRef), anyString());
// verify read group is not recreated
verify(mockedAuthorityService, never()).createAuthority(AuthorityType.GROUP, readGroup, readGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
readGroup = GROUP_PREFIX + readGroup;
verify(mockedAuthorityService, never()).addAuthority(GROUP_PREFIX + ROOT_IPR_GROUP, readGroup);
verify(mockedAuthorityService, never()).addAuthority(readGroup, USER);
verify(mockedAuthorityService, never()).addAuthority(readGroup, GROUP);
// verify write group is not recreated
verify(mockedAuthorityService, never()).createAuthority(AuthorityType.GROUP, writeGroup, writeGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
writeGroup = GROUP_PREFIX + writeGroup;
verify(mockedAuthorityService, never()).addAuthority(readGroup, writeGroup);
verify(mockedAuthorityService, never()).addAuthority(writeGroup, USER_W);
verify(mockedAuthorityService, never()).addAuthority(writeGroup, GROUP_W);
// verify groups assigned to RM roles
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_READERS, readGroup);
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_WRITERS, writeGroup);
// verify permissions are assigned to node
verify(mockedPermissionService).setPermission(nodeRef, readGroup, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService).setPermission(nodeRef, writeGroup, RMPermissionModel.FILING, true);
}
/**
* Given a node with no previous IPR groups assigned
* And existing IPR groups matches existing has, but not exact match
* When I add some read and write authorities
* Then new groups are created
* And they are assigned to the node
* And added to the RM roles
*/
@Test public void addExtendedSecurityForTheFirstTimeAndCreateGroupsAfterClash()
{
// group names
String readGroup = readGroupPrefix + "0";
String writeGroup = writeGroupPrefix + "0";
// setup query results
when(mockedReadPagingResults.getPage())
.thenReturn(Stream.of(GROUP_PREFIX + readGroup).collect(Collectors.toList()));
when(mockedAuthorityService.getAuthorities(
eq(AuthorityType.GROUP),
eq(RMAuthority.ZONE_APP_RM),
eq(readGroupPrefix),
eq(false),
eq(false),
any(PagingRequest.class)))
.thenReturn(mockedReadPagingResults);
when(mockedWritePagingResults.getPage())
.thenReturn(Stream.of(GROUP_PREFIX + writeGroup).collect(Collectors.toList()));
when(mockedAuthorityService.getAuthorities(
eq(AuthorityType.GROUP),
eq(RMAuthority.ZONE_APP_RM),
eq(writeGroupPrefix),
eq(false),
eq(false),
any(PagingRequest.class)))
.thenReturn(mockedWritePagingResults);
// setup exact match
when(mockedAuthorityService.authorityExists(GROUP_PREFIX + writeGroup))
.thenReturn(true);
when(mockedAuthorityService.getContainedAuthorities(null, GROUP_PREFIX + readGroup, true))
.thenReturn(Stream
.of(USER, GROUP, AlfMock.generateText())
.collect(Collectors.toSet()));
when(mockedAuthorityService.getContainedAuthorities(null, GROUP_PREFIX + writeGroup, true))
.thenReturn(Stream
.of(USER_W, AlfMock.generateText())
.collect(Collectors.toSet()));
// add extended security
extendedSecurityService.set(nodeRef, READERS, WRITERS);
// verify no old permissions needing to be cleared
verify(mockedPermissionService, never()).clearPermission(eq(nodeRef), anyString());
// new group names
readGroup = extendedSecurityService.getIPRGroupShortName(READER_GROUP_PREFIX, READERS, 1);
writeGroup = extendedSecurityService.getIPRGroupShortName(WRITER_GROUP_PREFIX, WRITERS, 1);
// verify read group created correctly
verify(mockedAuthorityService).createAuthority(AuthorityType.GROUP, readGroup, readGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
readGroup = GROUP_PREFIX + readGroup;
verify(mockedAuthorityService).addAuthority(GROUP_PREFIX + ROOT_IPR_GROUP, readGroup);
verify(mockedAuthorityService).addAuthority(readGroup, USER);
verify(mockedAuthorityService).addAuthority(readGroup, GROUP);
// verify write group created correctly
verify(mockedAuthorityService).createAuthority(AuthorityType.GROUP, writeGroup, writeGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
writeGroup = GROUP_PREFIX + writeGroup;
verify(mockedAuthorityService).addAuthority(GROUP_PREFIX + ROOT_IPR_GROUP, writeGroup);
verify(mockedAuthorityService).addAuthority(writeGroup, USER_W);
verify(mockedAuthorityService).addAuthority(writeGroup, GROUP_W);
// verify groups assigned to RM roles
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_READERS, readGroup);
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_WRITERS, writeGroup);
// verify permissions are assigned to node
verify(mockedPermissionService).setPermission(nodeRef, readGroup, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService).setPermission(nodeRef, writeGroup, RMPermissionModel.FILING, true);
}
/**
* Given a node with no previous IPR groups assigned
* And existing IPR groups matching, but found on second page of find results
* When I add some read and write authorities
* Then the existing IPR groups are used
* And they are assigned to the node
* And do not not need to be re-added to the RM roles
*/
@Test public void addExtendedSecurityWithResultPaging()
{
// group names
String readGroup = readGroupPrefix + "0";
String writeGroup = writeGroupPrefix + "0";
// create fity results
List<String> fiftyResults = new ArrayList<String>(50);
for (int i = 0; i < 50; i++)
{
fiftyResults.add(AlfMock.generateText());
}
// setup query results
when(mockedReadPagingResults.getPage())
.thenReturn(fiftyResults)
.thenReturn(Stream.of(GROUP_PREFIX + readGroup).collect(Collectors.toList()));
when(mockedAuthorityService.getAuthorities(
eq(AuthorityType.GROUP),
eq(RMAuthority.ZONE_APP_RM),
eq(readGroupPrefix),
eq(false),
eq(false),
any(PagingRequest.class)))
.thenReturn(mockedReadPagingResults);
when(mockedWritePagingResults.getPage())
.thenReturn(fiftyResults)
.thenReturn(Stream.of(GROUP_PREFIX + writeGroup).collect(Collectors.toList()));
when(mockedAuthorityService.getAuthorities(
eq(AuthorityType.GROUP),
eq(RMAuthority.ZONE_APP_RM),
eq(writeGroupPrefix),
eq(false),
eq(false),
any(PagingRequest.class)))
.thenReturn(mockedWritePagingResults);
// setup exact match
when(mockedAuthorityService.authorityExists(GROUP_PREFIX + writeGroup))
.thenReturn(true);
when(mockedAuthorityService.getContainedAuthorities(null, GROUP_PREFIX + readGroup, true))
.thenReturn(Stream
.of(USER, GROUP)
.collect(Collectors.toSet()));
when(mockedAuthorityService.getContainedAuthorities(null, GROUP_PREFIX + writeGroup, true))
.thenReturn(Stream
.of(USER_W, GROUP_W)
.collect(Collectors.toSet()));
// add extended security
extendedSecurityService.set(nodeRef, READERS, WRITERS);
// verify no old permissions needing to be cleared
verify(mockedPermissionService, never()).clearPermission(eq(nodeRef), anyString());
// verify read group is not recreated
verify(mockedAuthorityService, never()).createAuthority(AuthorityType.GROUP, readGroup, readGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
readGroup = GROUP_PREFIX + readGroup;
verify(mockedAuthorityService, never()).addAuthority(GROUP_PREFIX + ROOT_IPR_GROUP, readGroup);
verify(mockedAuthorityService, never()).addAuthority(readGroup, USER);
verify(mockedAuthorityService, never()).addAuthority(readGroup, GROUP);
// verify write group is not recreated
verify(mockedAuthorityService, never()).createAuthority(AuthorityType.GROUP, writeGroup, writeGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
writeGroup = GROUP_PREFIX + writeGroup;
verify(mockedAuthorityService, never()).addAuthority(readGroup, writeGroup);
verify(mockedAuthorityService, never()).addAuthority(writeGroup, USER_W);
verify(mockedAuthorityService, never()).addAuthority(writeGroup, GROUP_W);
// verify groups assigned to RM roles
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_READERS, readGroup);
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_WRITERS, writeGroup);
// verify permissions are assigned to node
verify(mockedPermissionService).setPermission(nodeRef, readGroup, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService).setPermission(nodeRef, writeGroup, RMPermissionModel.FILING, true);
}
/**
* Given that a node already has extended security
* When I add extended security
* Then the existing extended security is replaced with the new extended security
*/
@Test public void addExtendedSecurityToNodeWithExtendedSecurity()
{
// group names
String readGroup = extendedSecurityService.getIPRGroupShortName(READER_GROUP_FULL_PREFIX, READERS, 0);
String writeGroup = extendedSecurityService.getIPRGroupShortName(WRITER_GROUP_FULL_PREFIX, WRITERS, 0);
// setup permissions
Set<AccessPermission> permissions = Stream
.of(new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, readGroup, 0),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, AlfMock.generateText(), 1),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, writeGroup, 2))
.collect(Collectors.toSet());
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(permissions);
// set revised reader and writers
String user = generateText();
String group = generateText();
String userW = generateText();
String groupW = generateText();
Set<String> newReaders = Stream.of(user, group).collect(Collectors.toSet());
Set<String> newWriters = Stream.of(userW, groupW).collect(Collectors.toSet());
// new group names
String newReadGroup = extendedSecurityService.getIPRGroupShortName(READER_GROUP_PREFIX, newReaders, 0);
String newWriteGroup = extendedSecurityService.getIPRGroupShortName(WRITER_GROUP_PREFIX, newWriters, 0);
// make sure users and groups exist
Stream
.of(user, group, userW, groupW)
.forEach((a) ->
when(mockedAuthorityService.authorityExists(a))
.thenReturn(true));
// setup query results for no group matches
when(mockedReadPagingResults.getPage())
.thenReturn(Collections.emptyList());
when(mockedAuthorityService.getAuthorities(
eq(AuthorityType.GROUP),
eq(RMAuthority.ZONE_APP_RM),
any(String.class),
eq(false),
eq(false),
any(PagingRequest.class)))
.thenReturn(mockedReadPagingResults);
// set extended security
extendedSecurityService.set(nodeRef, newReaders, newWriters);
// verify that the old permissions are cleared
verify(mockedPermissionService).clearPermission(nodeRef, readGroup);
verify(mockedPermissionService).clearPermission(nodeRef, writeGroup);
// verify read group created correctly
verify(mockedAuthorityService).createAuthority(AuthorityType.GROUP, newReadGroup, newReadGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
newReadGroup = GROUP_PREFIX + newReadGroup;
verify(mockedAuthorityService).addAuthority(GROUP_PREFIX + ROOT_IPR_GROUP, newReadGroup);
verify(mockedAuthorityService).addAuthority(newReadGroup, user);
verify(mockedAuthorityService).addAuthority(newReadGroup, group);
// verify write group created correctly
verify(mockedAuthorityService).createAuthority(AuthorityType.GROUP, newWriteGroup, newWriteGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
newWriteGroup = GROUP_PREFIX + newWriteGroup;
verify(mockedAuthorityService).addAuthority(GROUP_PREFIX + ROOT_IPR_GROUP, newWriteGroup);
verify(mockedAuthorityService).addAuthority(newWriteGroup, userW);
verify(mockedAuthorityService).addAuthority(newWriteGroup, groupW);
// verify groups assigned to RM roles
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_READERS, newReadGroup);
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_WRITERS, newWriteGroup);
// verify permissions are assigned to node
verify(mockedPermissionService).setPermission(nodeRef, newReadGroup, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService).setPermission(nodeRef, newWriteGroup, RMPermissionModel.FILING, true);
}
/**
* Given that a node has renditions
* When I add extended security
* Then they are applied to the renditions
*/
@Test public void extendedSecurityAddedToRenditions()
{
// group names
String readGroup = extendedSecurityService.getIPRGroupShortName(READER_GROUP_PREFIX, READERS, 0);
String writeGroup = extendedSecurityService.getIPRGroupShortName(WRITER_GROUP_PREFIX, WRITERS, 0);
// setup query results
when(mockedReadPagingResults.getPage())
.thenReturn(Collections.emptyList());
when(mockedAuthorityService.getAuthorities(
eq(AuthorityType.GROUP),
eq(RMAuthority.ZONE_APP_RM),
any(String.class),
eq(false),
eq(false),
any(PagingRequest.class)))
.thenReturn(mockedReadPagingResults);
// setup renditions
NodeRef renditionNodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedNodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_RECORD))
.thenReturn(true);
when(mockedChildAssociationRef.getChildRef())
.thenReturn(renditionNodeRef);
when(mockedNodeService.getChildAssocs(nodeRef, RenditionModel.ASSOC_RENDITION, RegexQNamePattern.MATCH_ALL))
.thenReturn(Collections.singletonList(mockedChildAssociationRef));
// add extended security
extendedSecurityService.set(nodeRef, READERS, WRITERS);
// verify no old permissions needing to be cleared
verify(mockedPermissionService, never()).clearPermission(eq(nodeRef), anyString());
// verify read group created correctly
verify(mockedAuthorityService).createAuthority(AuthorityType.GROUP, readGroup, readGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
readGroup = GROUP_PREFIX + readGroup;
verify(mockedAuthorityService).addAuthority(GROUP_PREFIX + ROOT_IPR_GROUP, readGroup);
verify(mockedAuthorityService).addAuthority(readGroup, USER);
verify(mockedAuthorityService).addAuthority(readGroup, GROUP);
// verify write group created correctly
verify(mockedAuthorityService).createAuthority(AuthorityType.GROUP, writeGroup, writeGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
writeGroup = GROUP_PREFIX + writeGroup;
verify(mockedAuthorityService).addAuthority(GROUP_PREFIX + ROOT_IPR_GROUP, writeGroup);
verify(mockedAuthorityService).addAuthority(writeGroup, USER_W);
verify(mockedAuthorityService).addAuthority(writeGroup, GROUP_W);
// verify groups assigned to RM roles
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_READERS, readGroup);
verify(mockedFilePlanRoleService).assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_EXTENDED_WRITERS, writeGroup);
// verify permissions are assigned to node
verify(mockedPermissionService).setPermission(nodeRef, readGroup, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService).setPermission(nodeRef, writeGroup, RMPermissionModel.FILING, true);
// verify permissions are assigned to the rendition
verify(mockedPermissionService).setPermission(renditionNodeRef, readGroup, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService).setPermission(renditionNodeRef, writeGroup, RMPermissionModel.FILING, true);
}
/**
* Given that a node has extended security
* When I remove the extended security
* Then the inplace groups permissions are removed
*/
@Test public void removeAllExtendedSecurity()
{
// group names
String readGroup = extendedSecurityService.getIPRGroupShortName(READER_GROUP_FULL_PREFIX, READERS, 0);
String writeGroup = extendedSecurityService.getIPRGroupShortName(WRITER_GROUP_FULL_PREFIX, WRITERS, 0);
// setup permissions
Set<AccessPermission> permissions = Stream
.of(new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, readGroup, 0),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, AlfMock.generateText(), 1),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, writeGroup, 2))
.collect(Collectors.toSet());
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(permissions);
// remove extended security
extendedSecurityService.remove(nodeRef);
// verify that the groups permissions have been removed
verify(mockedPermissionService).clearPermission(nodeRef, readGroup);
verify(mockedPermissionService).clearPermission(nodeRef, writeGroup);
}
/**
* Given that a node has no extended security
* When I remove the extended security
* Then nothing happens
*/
@Test public void noExtendedSecurityToRemove()
{
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(HAS_NO_EXTENDED_SECURITY);
// remove extended security
extendedSecurityService.remove(nodeRef);
// verify that the groups permissions have been removed
verify(mockedPermissionService, never()).clearPermission(eq(nodeRef), anyString());
}
/**
* Given that node has renditions
* When I remove the extended security for a node
* Then the extended security is also removed from the renditions
*/
@Test public void removeExtendedSecurityFromRenditions()
{
// group names
String readGroup = extendedSecurityService.getIPRGroupShortName(READER_GROUP_FULL_PREFIX, READERS, 0);
String writeGroup = extendedSecurityService.getIPRGroupShortName(WRITER_GROUP_FULL_PREFIX, WRITERS, 0);
// setup renditions
NodeRef renditionNodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedNodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_RECORD))
.thenReturn(true);
when(mockedChildAssociationRef.getChildRef())
.thenReturn(renditionNodeRef);
when(mockedNodeService.getChildAssocs(nodeRef, RenditionModel.ASSOC_RENDITION, RegexQNamePattern.MATCH_ALL))
.thenReturn(Collections.singletonList(mockedChildAssociationRef));
// setup permissions
Set<AccessPermission> permissions = Stream
.of(new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, readGroup, 0),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, AlfMock.generateText(), 1),
new AccessPermissionImpl(AlfMock.generateText(), AccessStatus.ALLOWED, writeGroup, 2))
.collect(Collectors.toSet());
when(mockedPermissionService.getAllSetPermissions(nodeRef))
.thenReturn(permissions);
// remove extended security
extendedSecurityService.remove(nodeRef);
// verify that the groups permissions have been removed
verify(mockedPermissionService).clearPermission(nodeRef, readGroup);
verify(mockedPermissionService).clearPermission(nodeRef, writeGroup);
// verify that the groups permissions have been removed from the rendition
verify(mockedPermissionService).clearPermission(renditionNodeRef, readGroup);
verify(mockedPermissionService).clearPermission(renditionNodeRef, writeGroup);
}
}

View File

@@ -27,13 +27,10 @@
package org.alfresco.module.org_alfresco_module_rm.security; package org.alfresco.module.org_alfresco_module_rm.security;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@@ -173,15 +170,6 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
// verify permission set on target node // verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.READ_RECORDS, true); verify(mockedPermissionService, times(1)).setPermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordContainer, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify READ permission set down hierarchy
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordFolderChild, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService, times(1)).setPermission(unfiledRecord, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
} }
/** /**
@@ -195,14 +183,6 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
// verify permission set on target node // verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.FILING, true); verify(mockedPermissionService, times(1)).setPermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.FILING, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordContainer, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify FILING permission set down hierarchy
verify(mockedPermissionService, times(1)).setPermission(unfiledRecordFolderChild, AUTHORITY, RMPermissionModel.FILING, true);
verify(mockedPermissionService, times(1)).setPermission(unfiledRecord, AUTHORITY, RMPermissionModel.FILING, true);
} }
/** /**
@@ -216,14 +196,6 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
// verify permission deleted on target node // verify permission deleted on target node
verify(mockedPermissionService, times(1)).deletePermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.READ_RECORDS); verify(mockedPermissionService, times(1)).deletePermission(unfiledRecordFolder, AUTHORITY, RMPermissionModel.READ_RECORDS);
// verify no permissions deleted up the hierarchy
verify(mockedPermissionService, never()).deletePermission(eq(unfiledRecordContainer), eq(AUTHORITY), anyString());
verify(mockedPermissionService, never()).deletePermission(eq(filePlan), eq(AUTHORITY), anyString());
// verify READ permission removed down hierarchy
verify(mockedPermissionService, times(1)).deletePermission(unfiledRecordFolderChild, AUTHORITY, RMPermissionModel.READ_RECORDS);
verify(mockedPermissionService, times(1)).deletePermission(unfiledRecord, AUTHORITY, RMPermissionModel.READ_RECORDS);
} }
/** /**
@@ -237,16 +209,6 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
// verify permission set on target node // verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(holdContainer, AUTHORITY, RMPermissionModel.READ_RECORDS, true); verify(mockedPermissionService, times(1)).setPermission(holdContainer, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify READ permission set on hold
verify(mockedPermissionService, times(1)).setPermission(hold, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify permission not set on child of hold
verify(mockedPermissionService, never()).setPermission(eq(heldRecord), eq(AUTHORITY), anyString(), eq(true));
} }
/** /**
@@ -260,16 +222,6 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
// verify permission set on target node // verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(holdContainer, AUTHORITY, RMPermissionModel.FILING, true); verify(mockedPermissionService, times(1)).setPermission(holdContainer, AUTHORITY, RMPermissionModel.FILING, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify FILING permission set on hold
verify(mockedPermissionService, times(1)).setPermission(hold, AUTHORITY, RMPermissionModel.FILING, true);
// verify permission not set on child of hold
verify(mockedPermissionService, never()).setPermission(eq(heldRecord), eq(AUTHORITY), anyString(), eq(true));
} }
/** /**
@@ -283,13 +235,6 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
// verify permission set on target node // verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(hold, AUTHORITY, RMPermissionModel.READ_RECORDS, true); verify(mockedPermissionService, times(1)).setPermission(hold, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(holdContainer, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify permission not set on child of hold
verify(mockedPermissionService, never()).setPermission(eq(heldRecord), eq(AUTHORITY), anyString(), eq(true));
} }
/** /**
@@ -303,13 +248,6 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
// verify permission set on target node // verify permission set on target node
verify(mockedPermissionService, times(1)).setPermission(hold, AUTHORITY, RMPermissionModel.FILING, true); verify(mockedPermissionService, times(1)).setPermission(hold, AUTHORITY, RMPermissionModel.FILING, true);
// verify READ permission set up hierarchy
verify(mockedPermissionService, times(1)).setPermission(holdContainer, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
verify(mockedPermissionService, times(1)).setPermission(filePlan, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
// verify permission not set on child of hold
verify(mockedPermissionService, never()).setPermission(eq(heldRecord), eq(AUTHORITY), anyString(), eq(true));
} }
/** /**
@@ -323,23 +261,18 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
perms.add(new AccessPermissionImpl(RMPermissionModel.READ_RECORDS, AccessStatus.ALLOWED, AUTHORITY, 0)); perms.add(new AccessPermissionImpl(RMPermissionModel.READ_RECORDS, AccessStatus.ALLOWED, AUTHORITY, 0));
perms.add(new AccessPermissionImpl(RMPermissionModel.FILING, AccessStatus.ALLOWED, AUTHORITY2, 1)); perms.add(new AccessPermissionImpl(RMPermissionModel.FILING, AccessStatus.ALLOWED, AUTHORITY2, 1));
// setup in-place readers and writers
perms.add(new AccessPermissionImpl(RMPermissionModel.READ_RECORDS, AccessStatus.ALLOWED, ExtendedReaderDynamicAuthority.EXTENDED_READER, 2));
perms.add(new AccessPermissionImpl(RMPermissionModel.FILING, AccessStatus.ALLOWED, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, 3));
doReturn(perms).when(mockedPermissionService).getAllSetPermissions(nodeRef); doReturn(perms).when(mockedPermissionService).getAllSetPermissions(nodeRef);
} }
/** /**
* Helper to verify the core permissions have been initialized correctly * Helper to verify the core permissions have been initialized correctly
*/ */
private void verifyInitPermissions(NodeRef nodeRef) private void verifyInitPermissions(NodeRef nodeRef, boolean isInherited)
{ {
verify(mockedPermissionService, times(1)).setInheritParentPermissions(nodeRef, false); verify(mockedPermissionService).getAllSetPermissions(nodeRef);
verify(mockedPermissionService, times(1)).clearPermission(nodeRef, null); verify(mockedPermissionService).setInheritParentPermissions(nodeRef, isInherited);
verify(mockedPermissionService, times(1)).setPermission(nodeRef, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS, true); verify(mockedPermissionService).clearPermission(nodeRef, null);
verify(mockedPermissionService, times(1)).setPermission(nodeRef, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING, true); verify(mockedOwnableService).setOwner(nodeRef, OwnableService.NO_OWNER);
verify(mockedOwnableService, times(1)).setOwner(nodeRef, OwnableService.NO_OWNER);
} }
/** /**
@@ -350,21 +283,20 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
* @param read verification mode relating to setting read on the child * @param read verification mode relating to setting read on the child
* @param filling verification mode relating to setting filling on the child * @param filling verification mode relating to setting filling on the child
*/ */
private void verifyInitPermissions(NodeRef parent, NodeRef child, VerificationMode read, VerificationMode filling) private void verifyInitPermissions(NodeRef parent, NodeRef child, VerificationMode read, VerificationMode filling, boolean isParentFilePlan, boolean isInherited)
{ {
// verify the core permissions are set-up correctly // verify the core permissions are set-up correctly
verifyInitPermissions(child); verifyInitPermissions(child, isInherited);
if (isParentFilePlan)
{
// verify the permissions came from the correct parent // verify the permissions came from the correct parent
verify(mockedPermissionService).getAllSetPermissions(parent); verify(mockedPermissionService).getAllSetPermissions(parent);
// verify all the inherited permissions are set correctly (note read are not inherited from fileplan) // verify all the inherited permissions are set correctly (note read are not inherited from fileplan)
verify(mockedPermissionService, filling).setPermission(child, AUTHORITY2, RMPermissionModel.FILING, true); verify(mockedPermissionService, filling).setPermission(child, AUTHORITY2, RMPermissionModel.FILING, true);
verify(mockedPermissionService, read).setPermission(child, AUTHORITY, RMPermissionModel.READ_RECORDS, true); verify(mockedPermissionService, read).setPermission(child, AUTHORITY, RMPermissionModel.READ_RECORDS, true);
}
// verify that there are no unaccounted for interactions with the permission service
verifyNoMoreInteractions(mockedPermissionService);
} }
/** /**
@@ -380,7 +312,7 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
filePlanPermissionService.setupRecordCategoryPermissions(rootRecordCategory); filePlanPermissionService.setupRecordCategoryPermissions(rootRecordCategory);
// verify permission init // verify permission init
verifyInitPermissions(filePlan, rootRecordCategory, never(), times(1)); verifyInitPermissions(filePlan, rootRecordCategory, never(), times(1), true, false);
} }
/** /**
@@ -396,7 +328,7 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
filePlanPermissionService.setupRecordCategoryPermissions(recordCategory); filePlanPermissionService.setupRecordCategoryPermissions(recordCategory);
// verify permission init // verify permission init
verifyInitPermissions(rootRecordCategory, recordCategory, times(1), times(1)); verifyInitPermissions(rootRecordCategory, recordCategory, times(1), times(1), false, true);
} }
/** /**
@@ -412,7 +344,7 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
filePlanPermissionService.setupPermissions(recordCategory, newRecordFolder); filePlanPermissionService.setupPermissions(recordCategory, newRecordFolder);
// verify permission init // verify permission init
verifyInitPermissions(recordCategory, newRecordFolder, times(1), times(1)); verifyInitPermissions(recordCategory, newRecordFolder, times(1), times(1), false, true);
} }
@@ -429,7 +361,7 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
filePlanPermissionService.setupPermissions(newRecordFolder, newRecord); filePlanPermissionService.setupPermissions(newRecordFolder, newRecord);
// verify permission init // verify permission init
verifyInitPermissions(newRecordFolder, newRecord, times(1), times(1)); verifyInitPermissions(newRecordFolder, newRecord, times(1), times(1), false, true);
} }
/** /**
@@ -445,7 +377,7 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
filePlanPermissionService.setupPermissions(filePlan, holdContainer); filePlanPermissionService.setupPermissions(filePlan, holdContainer);
// verify permissions are set-up correctly // verify permissions are set-up correctly
verifyInitPermissions(filePlan, holdContainer, times(1), times(1)); verifyInitPermissions(filePlan, holdContainer, times(1), times(1), false, true);
} }
/** /**
@@ -461,7 +393,7 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
filePlanPermissionService.setupPermissions(holdContainer, hold); filePlanPermissionService.setupPermissions(holdContainer, hold);
// verify permissions are set-up correctly // verify permissions are set-up correctly
verifyInitPermissions(holdContainer, hold, never(), times(1)); verifyInitPermissions(holdContainer, hold, never(), times(1), false, false);
} }
@@ -478,7 +410,7 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
filePlanPermissionService.setupPermissions(filePlan, unfiledRecordContainer); filePlanPermissionService.setupPermissions(filePlan, unfiledRecordContainer);
// verify permissions are set-up correctly // verify permissions are set-up correctly
verifyInitPermissions(filePlan, unfiledRecordContainer, times(1), times(1)); verifyInitPermissions(filePlan, unfiledRecordContainer, times(1), times(1), false, false);
} }
/** /**
@@ -494,7 +426,7 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
filePlanPermissionService.setupPermissions(unfiledRecordContainer, unfiledRecordFolder); filePlanPermissionService.setupPermissions(unfiledRecordContainer, unfiledRecordFolder);
// verify permissions are set-up correctly // verify permissions are set-up correctly
verifyInitPermissions(unfiledRecordContainer, unfiledRecordFolder, never(), times(1)); verifyInitPermissions(unfiledRecordContainer, unfiledRecordFolder, never(), times(1), false, true);
} }
@@ -511,7 +443,7 @@ public class FilePlanPermissionServiceImplUnitTest extends BaseUnitTest
filePlanPermissionService.setupPermissions(unfiledRecordFolder, unfiledRecord); filePlanPermissionService.setupPermissions(unfiledRecordFolder, unfiledRecord);
// verify permission init // verify permission init
verifyInitPermissions(unfiledRecordFolder, unfiledRecord, times(1), times(1)); verifyInitPermissions(unfiledRecordFolder, unfiledRecord, times(1), times(1), false, true);
} }
} }

View File

@@ -0,0 +1,418 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* Copyright (C) 2005-2014 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.repo.web.scripts.roles;
import static java.util.Collections.emptyMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseWebScriptUnitTest;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.patch.PatchDAO;
import org.alfresco.repo.domain.qname.QNameDAO;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.Pair;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
/**
* DynamicAuthoritiesGet Unit Test
*
* @author Silviu Dinuta
*/
@SuppressWarnings("deprecation")
public class DynamicAuthoritiesGetUnitTest extends BaseWebScriptUnitTest implements RecordsManagementModel
{
/** test data */
private static final Long ASPECT_ID = 123l;
private static final QName ASPECT = AlfMock.generateQName();
/** mocks */
@Mock
private PatchDAO mockedPatchDAO;
@Mock
private NodeDAO mockedNodeDAO;
@Mock
private QNameDAO mockedQnameDAO;
@Mock
private NodeService mockedNodeService;
@Mock
private PermissionService mockedPermissionService;
@Mock
private ExtendedSecurityService mockedExtendedSecurityService;
@Mock
private TransactionService mockedTransactionService;
@Mock
private RetryingTransactionHelper mockedRetryingTransactionHelper;
/** test component */
@InjectMocks
private DynamicAuthoritiesGet webScript;
@Override
protected DeclarativeWebScript getWebScript()
{
return webScript;
}
@Override
protected String getWebScriptTemplate()
{
return "alfresco/templates/webscripts/org/alfresco/repository/roles/rm-dynamicauthorities.get.json.ftl";
}
/**
* Before test
*/
@SuppressWarnings("unchecked")
@Before
public void before()
{
MockitoAnnotations.initMocks(this);
webScript.setNodeService(mockedNodeService);
webScript.setPermissionService(mockedPermissionService);
webScript.setExtendedSecurityService(mockedExtendedSecurityService);
// setup retrying transaction helper
Answer<Object> doInTransactionAnswer = new Answer<Object>()
{
@SuppressWarnings("rawtypes")
@Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
RetryingTransactionCallback callback = (RetryingTransactionCallback) invocation.getArguments()[0];
return callback.execute();
}
};
doAnswer(doInTransactionAnswer).when(mockedRetryingTransactionHelper)
.<Object> doInTransaction(any(RetryingTransactionCallback.class), anyBoolean(), anyBoolean());
when(mockedTransactionService.getRetryingTransactionHelper()).thenReturn(mockedRetryingTransactionHelper);
// max node id
when(mockedPatchDAO.getMaxAdmNodeID()).thenReturn(500000L);
// aspect
when(mockedQnameDAO.getQName(ASPECT_EXTENDED_SECURITY)).thenReturn(new Pair<Long, QName>(ASPECT_ID, ASPECT));
}
/**
* Given that there are no nodes with the extended security aspect When the action is executed Nothing happens
* @throws Exception
*/
@SuppressWarnings({ "unchecked" })
@Test
public void noNodesWithExtendedSecurity() throws Exception
{
when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong()))
.thenReturn(Collections.emptyList());
// Set up parameters.
Map<String, String> parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "3");
JSONObject json = executeJSONWebScript(parameters);
assertNotNull(json);
String actualJSONString = json.toString();
// Check the JSON result using Jackson to allow easy equality testing.
ObjectMapper mapper = new ObjectMapper();
String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 0 records.\"}";
assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString));
verify(mockedNodeService, never()).getProperty(any(NodeRef.class), eq(PROP_READERS));
verify(mockedNodeService, never()).getProperty(any(NodeRef.class), eq(PROP_WRITERS));
verify(mockedNodeService, never()).removeAspect(any(NodeRef.class), eq(ASPECT_EXTENDED_SECURITY));
verify(mockedPermissionService, never()).clearPermission(any(NodeRef.class),
eq(ExtendedReaderDynamicAuthority.EXTENDED_READER));
verify(mockedPermissionService, never()).clearPermission(any(NodeRef.class),
eq(ExtendedWriterDynamicAuthority.EXTENDED_WRITER));
verify(mockedExtendedSecurityService, never()).set(any(NodeRef.class), any(Set.class), any(Set.class));
}
/**
* Given that there are records with the extended security aspect When the action is executed Then the aspect is
* removed And the dynamic authorities permissions are cleared And extended security is set via the updated API
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Test
public void recordsWithExtendedSecurityAspect() throws Exception
{
List<Long> ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList());
when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong()))
.thenReturn(ids)
.thenReturn(Collections.emptyList());
ids.stream().forEach((i) -> {
NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair<Long, NodeRef>(i, nodeRef));
when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(true);
when(mockedNodeService.getProperty(nodeRef, PROP_READERS))
.thenReturn((Serializable) Collections.emptyMap());
when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS))
.thenReturn((Serializable) Collections.emptyMap());
});
// Set up parameters.
Map<String, String> parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "4");
JSONObject json = executeJSONWebScript(parameters);
assertNotNull(json);
String actualJSONString = json.toString();
ObjectMapper mapper = new ObjectMapper();
String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 3 records.\"}";
assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString));
verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_READERS));
verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_WRITERS));
verify(mockedNodeService, times(3)).removeAspect(any(NodeRef.class), eq(ASPECT_EXTENDED_SECURITY));
verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class),
eq(ExtendedReaderDynamicAuthority.EXTENDED_READER));
verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class),
eq(ExtendedWriterDynamicAuthority.EXTENDED_WRITER));
verify(mockedExtendedSecurityService, times(3)).set(any(NodeRef.class), any(Set.class), any(Set.class));
}
/**
* Given that there are non-records with the extended security aspect When the web script is executed Then the aspect is
* removed And the dynamic authorities permissions are cleared
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Test
public void nonRecordsWithExtendedSecurityAspect() throws Exception
{
List<Long> ids = Stream.of(1l, 2l, 3l).collect(Collectors.toList());
when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong()))
.thenReturn(ids)
.thenReturn(Collections.emptyList());
ids.stream().forEach((i) -> {
NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair<Long, NodeRef>(i, nodeRef));
when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(false);
when(mockedNodeService.getProperty(nodeRef, PROP_READERS))
.thenReturn((Serializable) Collections.emptyMap());
when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS))
.thenReturn((Serializable) Collections.emptyMap());
});
// Set up parameters.
Map<String, String> parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "4");
JSONObject json = executeJSONWebScript(parameters);
assertNotNull(json);
String actualJSONString = json.toString();
ObjectMapper mapper = new ObjectMapper();
String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 3 records.\"}";
assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString));
verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_READERS));
verify(mockedNodeService, times(3)).getProperty(any(NodeRef.class), eq(PROP_WRITERS));
verify(mockedNodeService, times(3)).removeAspect(any(NodeRef.class), eq(ASPECT_EXTENDED_SECURITY));
verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class),
eq(ExtendedReaderDynamicAuthority.EXTENDED_READER));
verify(mockedPermissionService, times(3)).clearPermission(any(NodeRef.class),
eq(ExtendedWriterDynamicAuthority.EXTENDED_WRITER));
verify(mockedExtendedSecurityService, never()).set(any(NodeRef.class), any(Set.class), any(Set.class));
}
@Test
public void missingBatchSizeParameter() throws Exception
{
JSONObject json = executeJSONWebScript(emptyMap());
assertNotNull(json);
String actualJSONString = json.toString();
ObjectMapper mapper = new ObjectMapper();
String expectedJSONString = "{\"responsestatus\":\"failed\",\"message\":\"Parameter batchsize is mandatory\"}";
assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString));
}
@Test
public void invalidBatchSizeParameter() throws Exception
{
// Set up parameters.
Map<String, String> parameters = ImmutableMap.of("batchsize", "dd");
JSONObject json = executeJSONWebScript(parameters);
assertNotNull(json);
String actualJSONString = json.toString();
ObjectMapper mapper = new ObjectMapper();
String expectedJSONString = "{\"responsestatus\":\"failed\",\"message\":\"Parameter batchsize is invalid.\"}";
assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString));
}
@Test
public void batchSizeShouldBeGraterThanZero() throws Exception
{
when(mockedQnameDAO.getQName(ASPECT_EXTENDED_SECURITY)).thenReturn(null);
// Set up parameters.
Map<String, String> parameters = ImmutableMap.of("batchsize", "0");
JSONObject json = executeJSONWebScript(parameters);
assertNotNull(json);
String actualJSONString = json.toString();
ObjectMapper mapper = new ObjectMapper();
String expectedJSONString = "{\"responsestatus\":\"failed\",\"message\":\"Parameter batchsize should be a number greater than 0.\"}";
assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString));
}
@Test
public void extendedSecurityAspectNotCreated() throws Exception
{
when(mockedQnameDAO.getQName(ASPECT_EXTENDED_SECURITY)).thenReturn(null);
// Set up parameters.
Map<String, String> parameters = ImmutableMap.of("batchsize", "3");
JSONObject json = executeJSONWebScript(parameters);
assertNotNull(json);
String actualJSONString = json.toString();
ObjectMapper mapper = new ObjectMapper();
String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"There where no records to be processed.\"}";
assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString));
}
@Test
public void processAllRecordsWhenMaxProcessedRecordsIsZero() throws Exception
{
List<Long> ids = Stream.of(1l, 2l, 3l,4l).collect(Collectors.toList());
when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong()))
.thenReturn(ids)
.thenReturn(Collections.emptyList());
ids.stream().forEach((i) -> {
NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair<Long, NodeRef>(i, nodeRef));
when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(false);
when(mockedNodeService.getProperty(nodeRef, PROP_READERS))
.thenReturn((Serializable) Collections.emptyMap());
when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS))
.thenReturn((Serializable) Collections.emptyMap());
});
// Set up parameters.
Map<String, String> parameters = ImmutableMap.of("batchsize", "10", "maxProcessedRecords", "0");
JSONObject json = executeJSONWebScript(parameters);
assertNotNull(json);
String actualJSONString = json.toString();
ObjectMapper mapper = new ObjectMapper();
String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed 4 records.\"}";
assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString));
}
@Test
public void whenMaxProcessedRecordsIsMissingItDefaultsToBatchSize() throws Exception
{
List<Long> ids = Stream.of(1l, 2l, 3l, 4l, 5l).collect(Collectors.toList());
when(mockedPatchDAO.getNodesByAspectQNameId(eq(ASPECT_ID), anyLong(), anyLong()))
.thenReturn(ids)
.thenReturn(Collections.emptyList());
ids.stream().forEach((i) -> {
NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService);
when(mockedNodeDAO.getNodePair(i)).thenReturn(new Pair<Long, NodeRef>(i, nodeRef));
when(mockedNodeService.hasAspect(nodeRef, ASPECT_RECORD)).thenReturn(false);
when(mockedNodeService.getProperty(nodeRef, PROP_READERS))
.thenReturn((Serializable) Collections.emptyMap());
when(mockedNodeService.getProperty(nodeRef, PROP_WRITERS))
.thenReturn((Serializable) Collections.emptyMap());
});
// Set up parameters.
Map<String, String> parameters = ImmutableMap.of("batchsize", "4");
JSONObject json = executeJSONWebScript(parameters);
assertNotNull(json);
String actualJSONString = json.toString();
ObjectMapper mapper = new ObjectMapper();
String expectedJSONString = "{\"responsestatus\":\"success\",\"message\":\"Processed first 4 records.\"}";
assertEquals(mapper.readTree(expectedJSONString), mapper.readTree(actualJSONString));
}
}