diff --git a/pom.xml b/pom.xml
index 06cc4d693c..2487228b3c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,6 +78,7 @@
false1.7
+ 1.8UTF-8-Xmx1024m -XX:MaxPermSize=256m -Duser.language=en -Dcom.sun.management.jmxremote
@@ -148,6 +149,19 @@
${maven.build.sourceVersion}${maven.build.sourceVersion}
+
+
+ default-testCompile
+ process-test-sources
+
+ testCompile
+
+
+ ${maven.build.testSourceVersion}
+ ${maven.build.testSourceVersion}
+
+
+ maven-deploy-plugin
diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/extended-repository-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/extended-repository-context.xml
index 6f589e52b4..7e0ed6021b 100644
--- a/rm-server/config/alfresco/module/org_alfresco_module_rm/extended-repository-context.xml
+++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/extended-repository-context.xml
@@ -58,6 +58,7 @@
org.alfresco.service.cmr.security.PermissionService.hasPermission=ACL_ALLOW
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.getReadersAndWriters=ACL_METHOD.ROLE_ADMINISTRATOR
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.setPermission=ACL_NODE.0.sys:base.ChangePermissions
diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml
index d42f1b3bda..6afcedfb33 100644
--- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml
+++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml
@@ -569,7 +569,10 @@
parent="baseService">
-
+
+
+
+
diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml
index ce01a26573..d8ad239912 100644
--- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml
+++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-version-context.xml
@@ -22,7 +22,6 @@
-
diff --git a/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/DeprecatedExtendedSecurityService.java b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/DeprecatedExtendedSecurityService.java
new file mode 100644
index 0000000000..b844594bf0
--- /dev/null
+++ b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/DeprecatedExtendedSecurityService.java
@@ -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 .
+ * #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 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 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 readers, Set writers);
+
+ /**
+ * Add extended security for the specified authorities to a node.
+ *
+ * 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 readers, Set 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 readers, Set writers);
+
+ /**
+ * Remove the extended security for the specified authorities from a node.
+ *
+ * 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 readers, Set 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);
+}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java
similarity index 84%
rename from rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java
rename to rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java
index 443414e66d..27b6c97292 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java
+++ b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/ExtendedReaderDynamicAuthority.java
@@ -1,21 +1,30 @@
/*
- * Copyright (C) 2005-2014 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
+ * #%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 .
+ * #L%
*/
+
package org.alfresco.module.org_alfresco_module_rm.security;
import java.util.Collections;
@@ -32,6 +41,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
* @author Roy Wetherall
* @since 2.1
*/
+@Deprecated
public class ExtendedReaderDynamicAuthority extends ExtendedSecurityBaseDynamicAuthority
{
/** Extended reader role */
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityBaseDynamicAuthority.java b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityBaseDynamicAuthority.java
similarity index 90%
rename from rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityBaseDynamicAuthority.java
rename to rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityBaseDynamicAuthority.java
index 8f3cb2f44d..c6b676a230 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityBaseDynamicAuthority.java
+++ b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityBaseDynamicAuthority.java
@@ -1,21 +1,30 @@
/*
- * Copyright (C) 2005-2014 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
+ * #%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 .
+ * #L%
*/
+
package org.alfresco.module.org_alfresco_module_rm.security;
import java.util.Map;
@@ -39,6 +48,7 @@ import org.springframework.context.ApplicationContextAware;
* @author Roy Wetherall
* @since 2.1
*/
+@Deprecated
public abstract class ExtendedSecurityBaseDynamicAuthority implements DynamicAuthority,
RecordsManagementModel,
ApplicationContextAware
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedWriterDynamicAuthority.java b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/ExtendedWriterDynamicAuthority.java
similarity index 85%
rename from rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedWriterDynamicAuthority.java
rename to rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/ExtendedWriterDynamicAuthority.java
index c27faa6edf..787e3c7eb8 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedWriterDynamicAuthority.java
+++ b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/ExtendedWriterDynamicAuthority.java
@@ -1,21 +1,30 @@
/*
- * Copyright (C) 2005-2014 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
+ * #%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 .
+ * #L%
*/
+
package org.alfresco.module.org_alfresco_module_rm.security;
import java.util.Collections;
@@ -33,6 +42,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
* @author Roy Wetherall
* @since 2.1
*/
+@Deprecated
public class ExtendedWriterDynamicAuthority extends ExtendedSecurityBaseDynamicAuthority
{
/** Extended writer role */
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationService.java b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationService.java
similarity index 75%
rename from rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationService.java
rename to rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationService.java
index 72bcc8adaa..af9f9f22ed 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationService.java
+++ b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationService.java
@@ -1,21 +1,30 @@
/*
- * Copyright (C) 2005-2014 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
+ * #%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 .
+ * #L%
*/
+
package org.alfresco.module.org_alfresco_module_rm.security;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
@@ -26,6 +35,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
*
* @author Roy Wetherall
* @since 2.1
+ * @deprecated as of 2.2, use {@link AuthenticationUtil}.
*/
public interface FilePlanAuthenticationService
{
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationServiceImpl.java b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationServiceImpl.java
similarity index 79%
rename from rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationServiceImpl.java
rename to rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationServiceImpl.java
index 76f036022e..8055fa5301 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationServiceImpl.java
+++ b/rm-server/source/compatibility/org/alfresco/module/org_alfresco_module_rm/security/FilePlanAuthenticationServiceImpl.java
@@ -1,21 +1,30 @@
/*
- * Copyright (C) 2005-2014 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
+ * #%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 .
+ * #L%
*/
+
package org.alfresco.module.org_alfresco_module_rm.security;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
@@ -25,6 +34,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
* @author Roy Wetherall
* @since 2.1
*/
+@Deprecated
public class FilePlanAuthenticationServiceImpl implements FilePlanAuthenticationService
{
/** Default rm admin user values */
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java
index 1d946695fb..d9565bc074 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/DeclareRecordAction.java
@@ -48,6 +48,9 @@ import org.springframework.extensions.surf.util.I18NUtil;
*/
public class DeclareRecordAction extends RMActionExecuterAbstractBase
{
+ /** action name */
+ public static final String NAME = "declareRecord";
+
/** I18N */
private static final String MSG_UNDECLARED_ONLY_RECORDS = "rm.action.undeclared-only-records";
private static final String MSG_NO_DECLARE_MAND_PROP = "rm.action.no-declare-mand-prop";
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/fileplan/FilePlanServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/fileplan/FilePlanServiceImpl.java
index 111212b7a4..7bc57fb327 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/fileplan/FilePlanServiceImpl.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/fileplan/FilePlanServiceImpl.java
@@ -33,11 +33,10 @@ import org.alfresco.model.ContentModel;
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.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.repo.cache.SimpleCache;
import org.alfresco.repo.domain.node.NodeDAO;
+import org.alfresco.repo.rule.RuleModel;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -347,23 +346,12 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
containerType,
properties).getChildRef();
- // if (!inheritPermissions)
- // {
- // set inheritance to false
- getPermissionService().setInheritParentPermissions(container, false);
- 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);
-
- // TODO set the admin users to have filing permissions on the unfiled container!!!
- // TODO we will need to be able to get a list of the admin roles from the service
- // }
- // else
- // {
- // just inherit eveything
- // TODO will change this when we are able to set permissions on holds and transfers!
- // getPermissionService().setInheritParentPermissions(container, true);
- // }
+ // set inheritance to false
+ getPermissionService().setInheritParentPermissions(container, false);
+ getPermissionService().setPermission(container, allRoles, RMPermissionModel.READ_RECORDS, true);
+
+ // prevent inheritance of rules
+ nodeService.addAspect(container, RuleModel.ASPECT_IGNORE_INHERITED_RULES, null);
return container;
}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java
index 481afd29cd..2736a86f08 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java
@@ -242,9 +242,10 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel
QName PROP_LOADED_DATA_SET_IDS = QName.createQName(RM_URI, "loadedDataSetIds");
// Extended security aspect
- QName ASPECT_EXTENDED_SECURITY = QName.createQName(RM_URI, "extendedSecurity");
- QName PROP_READERS = QName.createQName(RM_URI, "readers");
- QName PROP_WRITERS = QName.createQName(RM_URI, "writers");
+ // @deprecated as of 2.5, because of performance issues
+ @Deprecated QName ASPECT_EXTENDED_SECURITY = QName.createQName(RM_URI, "extendedSecurity");
+ @Deprecated QName PROP_READERS = QName.createQName(RM_URI, "readers");
+ @Deprecated QName PROP_WRITERS = QName.createQName(RM_URI, "writers");
// Originating details of a record
QName ASPECT_RECORD_ORIGINATING_DETAILS = QName.createQName(RM_URI, "recordOriginatingDetails");
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java
index 8f8f8019c9..ece8737a67 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/RecordAspect.java
@@ -30,6 +30,7 @@ import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.repo.copy.CopyBehaviourCallback;
import org.alfresco.repo.copy.CopyDetails;
+import org.alfresco.repo.copy.CopyServicePolicies;
import org.alfresco.repo.copy.DefaultCopyBehaviourCallback;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
@@ -57,7 +58,8 @@ public class RecordAspect extends AbstractDisposableItem
implements NodeServicePolicies.OnCreateChildAssociationPolicy,
RecordsManagementPolicies.OnCreateReference,
RecordsManagementPolicies.OnRemoveReference,
- NodeServicePolicies.OnMoveNodePolicy
+ NodeServicePolicies.OnMoveNodePolicy,
+ CopyServicePolicies.OnCopyCompletePolicy
{
/** Well-known location of the scripts folder. */
// TODO make configurable
@@ -124,11 +126,11 @@ public class RecordAspect extends AbstractDisposableItem
// manage any extended readers
NodeRef parent = childAssocRef.getParentRef();
- Set readers = extendedSecurityService.getExtendedReaders(parent);
- Set writers = extendedSecurityService.getExtendedWriters(parent);
+ Set readers = extendedSecurityService.getReaders(parent);
+ Set writers = extendedSecurityService.getWriters(parent);
if (readers != null && readers.size() != 0)
{
- extendedSecurityService.addExtendedSecurity(thumbnail, readers, writers, false);
+ extendedSecurityService.set(thumbnail, readers, writers);
}
}
@@ -288,4 +290,33 @@ public class RecordAspect extends AbstractDisposableItem
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 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);
+ }
+ }
}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/v21/RMv21InPlacePatch.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/v21/RMv21InPlacePatch.java
index 5ec24cdee3..d3a02070cb 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/v21/RMv21InPlacePatch.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/v21/RMv21InPlacePatch.java
@@ -25,13 +25,10 @@ import java.util.Set;
import org.alfresco.model.ContentModel;
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.RMPermissionModel;
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.model.RecordsManagementModel;
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.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -155,10 +152,6 @@ public class RMv21InPlacePatch extends RMv21PatchComponent
ruleService.disableRules();
try
{
- // set permissions
- filePlanPermissionService.setPermission(filePlan, ExtendedReaderDynamicAuthority.EXTENDED_READER, RMPermissionModel.READ_RECORDS);
- filePlanPermissionService.setPermission(filePlan, ExtendedWriterDynamicAuthority.EXTENDED_WRITER, RMPermissionModel.FILING);
-
// create fileplan containers
filePlanService.createHoldContainer(filePlan);
filePlanService.createTransferContainer(filePlan);
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/InplaceRecordServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/InplaceRecordServiceImpl.java
index 16bd7effb9..8132f465f7 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/InplaceRecordServiceImpl.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/InplaceRecordServiceImpl.java
@@ -21,7 +21,6 @@ package org.alfresco.module.org_alfresco_module_rm.record;
import static org.alfresco.model.ContentModel.ASPECT_PENDING_DELETE;
import java.util.List;
-import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
@@ -95,22 +94,26 @@ public class InplaceRecordServiceImpl extends ServiceBaseImpl implements Inplace
{
// remove the child association
NodeRef originatingLocation = (NodeRef) nodeService.getProperty(nodeRef, PROP_RECORD_ORIGINATING_LOCATION);
- List parentAssocs = nodeService.getParentAssocs(nodeRef);
- for (ChildAssociationRef childAssociationRef : parentAssocs)
+
+ if (originatingLocation != null)
{
- if (!childAssociationRef.isPrimary() &&
- childAssociationRef.getParentRef().equals(originatingLocation) &&
- !nodeService.hasAspect(childAssociationRef.getChildRef(), ASPECT_PENDING_DELETE))
+ List parentAssocs = nodeService.getParentAssocs(nodeRef);
+ for (ChildAssociationRef childAssociationRef : parentAssocs)
{
- nodeService.removeChildAssociation(childAssociationRef);
- break;
+ if (!childAssociationRef.isPrimary() &&
+ childAssociationRef.getParentRef().equals(originatingLocation) &&
+ !nodeService.hasAspect(childAssociationRef.getChildRef(), ASPECT_PENDING_DELETE))
+ {
+ nodeService.removeChildAssociation(childAssociationRef);
+ break;
+ }
}
+
+ // remove the extended security from the node
+ // this prevents the users from continuing to see the record in searchs and other linked locations
+ extendedSecurityService.remove(nodeRef);
}
- // remove the extended security from the node
- // this prevents the users from continuing to see the record in searchs and other linked locations
- extendedSecurityService.removeAllExtendedSecurity(nodeRef);
-
return null;
}
});
@@ -164,18 +167,11 @@ public class InplaceRecordServiceImpl extends ServiceBaseImpl implements Inplace
{
try
{
- // Get the extended readers/writers
- Set extendedReaders = extendedSecurityService.getExtendedReaders(nodeRef);
- Set extendedWriters = extendedSecurityService.getExtendedWriters(nodeRef);
-
// Move the record
fileFolderService.moveFrom(nodeRef, source, targetNodeRef, null);
// Update the originating location property
nodeService.setProperty(nodeRef, PROP_RECORD_ORIGINATING_LOCATION, targetNodeRef);
-
- // Set the extended readers/writers
- extendedSecurityService.addExtendedSecurity(nodeRef, extendedReaders, extendedWriters);
}
catch (FileExistsException | FileNotFoundException ex)
{
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java
index 0432c1c086..1536c6f942 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java
@@ -100,6 +100,7 @@ import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.EqualsHelper;
+import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyMap;
import org.apache.commons.lang.ArrayUtils;
@@ -242,10 +243,6 @@ public class RecordServiceImpl extends BaseBehaviourBean
this,
"onCreateChildAssociation",
NotificationFrequency.FIRST_EVENT);
- private JavaBehaviour onDeleteDeclaredRecordLink = new JavaBehaviour(
- this,
- "onDeleteDeclaredRecordLink",
- NotificationFrequency.FIRST_EVENT);
/**
* @param identifierService identifier service
@@ -398,11 +395,6 @@ public class RecordServiceImpl extends BaseBehaviourBean
TYPE_RECORD_FOLDER,
ContentModel.ASSOC_CONTAINS,
onCreateChildAssociation);
- policyComponent.bindAssociationBehaviour(
- NodeServicePolicies.BeforeDeleteChildAssociationPolicy.QNAME,
- ContentModel.TYPE_FOLDER,
- ContentModel.ASSOC_CONTAINS,
- onDeleteDeclaredRecordLink);
}
/**
@@ -573,27 +565,6 @@ public class RecordServiceImpl extends BaseBehaviourBean
}, 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()
*/
@@ -887,12 +858,10 @@ public class RecordServiceImpl extends BaseBehaviourBean
throw new AlfrescoRuntimeException("Unable to create record, because new record container could not be found.");
}
- // get the documents readers
- Long aclId = nodeService.getNodeAclId(nodeRef);
- Set readers = extendedPermissionService.getReaders(aclId);
- Set writers = extendedPermissionService.getWriters(aclId);
+ // get the documents readers and writers
+ Pair, Set> readersAndWriters = extendedPermissionService.getReadersAndWriters(nodeRef);
- // add the current owner to the list of extended writers
+ // get the current owner
String owner = ownableService.getOwner(nodeRef);
// get the documents primary parent assoc
@@ -944,13 +913,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
nodeService.addChild(parentAssoc.getParentRef(), nodeRef, parentAssoc.getTypeQName(), parentAssoc.getQName());
// set the extended security
- Set combinedWriters = new HashSet(writers);
- if (owner != null && !owner.isEmpty() && !owner.equals(OwnableService.NO_OWNER))
- {
- combinedWriters.add(owner);
- }
- combinedWriters.add(AuthenticationUtil.getFullyAuthenticatedUser());
- extendedSecurityService.addExtendedSecurity(nodeRef, readers, combinedWriters);
+ extendedSecurityService.set(nodeRef, readersAndWriters);
}
finally
{
@@ -982,24 +945,8 @@ public class RecordServiceImpl extends BaseBehaviourBean
// get the unfiled record folder
final NodeRef unfiledRecordFolder = filePlanService.getUnfiledContainer(filePlan);
- // get the documents readers
- Long aclId = nodeService.getNodeAclId(nodeRef);
- Set readers = extendedPermissionService.getReaders(aclId);
- Set writers = extendedPermissionService.getWriters(aclId);
-
- // add the current owner to the list of extended writers
- Set modifiedWrtiers = new HashSet(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());
+ // get the documents readers and writers
+ Pair, Set> readersAndWriters = extendedPermissionService.getReadersAndWriters(nodeRef);
// copy version state and create record
NodeRef record = null;
@@ -1056,7 +1003,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
}
// set extended security on record
- extendedSecurityService.addExtendedSecurity(record, readers, writers);
+ extendedSecurityService.set(record, readersAndWriters);
return record;
}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/role/FilePlanRoleServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/role/FilePlanRoleServiceImpl.java
index b9c65bcf43..1cb0b151c3 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/role/FilePlanRoleServiceImpl.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/role/FilePlanRoleServiceImpl.java
@@ -36,8 +36,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.fileplan.FilePlanService;
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.authority.RMAuthority;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -185,8 +183,6 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService,
// Set the permissions
permissionService.setInheritParentPermissions(filePlan, false);
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
systemContainers.add(filePlanService.createHoldContainer(filePlan));
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityService.java
index a28d66fe53..afa06f4fdb 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityService.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityService.java
@@ -1,117 +1,105 @@
/*
- * Copyright (C) 2005-2014 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
+ * #%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 .
+ * #L%
*/
+
package org.alfresco.module.org_alfresco_module_rm.security;
import java.util.Set;
+import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.util.Pair;
/**
* Extended security service.
- *
+ *
* @author Roy Wetherall
* @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.
- *
+ *
* @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);
-
+
/**
* 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
*/
- Set getExtendedReaders(NodeRef nodeRef);
-
+ Set getReaders(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
*/
- Set getExtendedWriters(NodeRef nodeRef);
-
- /**
- * Add extended security for the specified authorities to a node.
- *
- * @param nodeRef node reference
- * @param readers set of authorities to add extended read permissions
- * @param writers set of authorities to add extended write permissions
- */
- void addExtendedSecurity(NodeRef nodeRef, Set readers, Set writers);
+ Set 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 readersAndWriters pair where first is the set of readers and the
+ * second is the set of writers
+ */
+ void set(NodeRef nodeRef, Pair, Set> readersAndWriters);
+
+ /**
+ * 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.
*
- * 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.
+ * Note it is vaild to provide 'null' values for readers and/or writers.
*
* @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.
- */
- void addExtendedSecurity(NodeRef nodeRef, Set readers, Set writers, boolean applyToParents);
-
- /**
- * Remove the extended security for the specified authorities from a node.
+ * @param readers set of readers
+ * @param writers set of writers
*
- * @param nodeRef node reference
- * @param readers set of authorities to remove as extended readers
- * @param writers set of authorities to remove as extended writers
+ * @since 2.5
*/
- void removeExtendedSecurity(NodeRef nodeRef, Set readers, Set writers);
+ void set(NodeRef nodeRef, Set readers, Set writers);
/**
- * Remove the extended security for the specified authorities from a node.
- *
- * 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 readers, Set writers, boolean applyToParents);
-
- /**
- * Remove all extended readers and writers from the given node reference.
+ * Removes all extended security from a node.
*
* @param nodeRef node reference
*/
- void removeAllExtendedSecurity(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);
+ void remove(NodeRef nodeRef);
}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityServiceImpl.java
index 099904fa9b..08ddbd2cd5 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityServiceImpl.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/ExtendedSecurityServiceImpl.java
@@ -1,42 +1,62 @@
/*
- * Copyright (C) 2005-2014 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
+ * #%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 .
+ * #L%
*/
+
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.Map;
import java.util.Set;
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.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.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.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
+import org.alfresco.service.transaction.TransactionService;
+import org.alfresco.util.Pair;
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.
@@ -46,17 +66,31 @@ import org.alfresco.util.ParameterCheck;
*/
public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
implements ExtendedSecurityService,
- RecordsManagementModel
+ RecordsManagementModel,
+ ApplicationListener
{
- /** Ad hoc properties used for reference counting */
- private static final QName PROP_EXTENDED_READER_ROLE = QName.createQName(RM_URI, "extendedReaderRole");
- private static final QName PROP_EXTENDED_WRITER_ROLE = QName.createQName(RM_URI, "extendedWriterRole");
-
+ /** 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 */
private FilePlanService filePlanService;
/** File plan role service */
private FilePlanRoleService filePlanRoleService;
+
+ /** authority service */
+ private AuthorityService authorityService;
+
+ /** permission service */
+ private PermissionService permissionService;
+
+ /** transaction service */
+ private TransactionService transactionService;
/**
* @param filePlanService file plan service
@@ -73,115 +107,153 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
{
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()
+ {
+ 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)
*/
+ @Override
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")
@Override
- public Set getExtendedReaders(NodeRef nodeRef)
- {
- Set result = null;
-
- Map readerMap = (Map)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 getExtendedWriters(NodeRef nodeRef)
- {
- Set result = null;
-
- Map map = (Map)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 readers, Set 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 readers, Set writers, boolean applyToParents)
+ public Set getReaders(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
- ParameterCheck.mandatory("applyToParents", applyToParents);
-
- if (nodeRef != null)
+
+ Set result = Collections.EMPTY_SET;
+ Pair iprGroups = getIPRGroups(nodeRef);
+ if (iprGroups != null)
{
- addExtendedSecurityImpl(nodeRef, readers, writers, applyToParents);
+ result = getAuthorities(iprGroups.getFirst());
}
+
+ return result;
}
/**
- * Add extended security implementation method
- *
- * @param nodeRef
- * @param readers
- * @param writers
- * @param applyToParents
+ * @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#getWriters(org.alfresco.service.cmr.repository.NodeRef)
*/
@SuppressWarnings("unchecked")
- private void addExtendedSecurityImpl(NodeRef nodeRef, Set readers, Set writers, boolean applyToParents)
+ @Override
+ public Set getWriters(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
- ParameterCheck.mandatory("applyToParents", applyToParents);
-
- // add the aspect if missing
- if (!nodeService.hasAspect(nodeRef, ASPECT_EXTENDED_SECURITY))
+
+ Set result = Collections.EMPTY_SET;
+ Pair iprGroups = getIPRGroups(nodeRef);
+ if (iprGroups != null)
{
- nodeService.addAspect(nodeRef, ASPECT_EXTENDED_SECURITY, null);
+ result = getAuthorities(iprGroups.getSecond());
}
-
- // update the readers map
- if (readers != null && readers.size() != 0)
- {
- // get reader map
- Map readersMap = (Map)nodeService.getProperty(nodeRef, PROP_READERS);
-
- // set the readers property (this will in turn apply the aspect if required)
- nodeService.setProperty(nodeRef, PROP_READERS, (Serializable)addToMap(readersMap, readers));
- }
-
- // update the writers map
- if (writers != null && writers.size() != 0)
- {
- // get writer map
- Map writersMap = (Map)nodeService.getProperty(nodeRef, PROP_WRITERS);
-
- // set the writers property (this will in turn apply the aspect if required)
- nodeService.setProperty(nodeRef, PROP_WRITERS, (Serializable)addToMap(writersMap, writers));
- }
-
+
+ return result;
+ }
+
+ /**
+ * Helper to get authorities for a given group
+ *
+ * @param group group name
+ * @return Set immediate authorities
+ */
+ private Set getAuthorities(String group)
+ {
+ Set result = new HashSet();
+ 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> readersAndWriters)
+ {
+ ParameterCheck.mandatory("nodeRef", nodeRef);
+
+ set(nodeRef, readersAndWriters.getFirst(), readersAndWriters.getSecond());
+ }
+
+ /**
+ * @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 readers, Set writers)
+ {
+ ParameterCheck.mandatory("nodeRef", nodeRef);
+
+ // remove existing extended security, assuming there is any
+ remove(nodeRef);
+
+ // find groups
+ Pair 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
if (isRecord(nodeRef))
{
@@ -189,130 +261,300 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
for (ChildAssociationRef assoc : assocs)
{
NodeRef child = assoc.getChildRef();
- addExtendedSecurityImpl(child, readers, writers, false);
+ assignIPRGroupsToNode(iprGroups, child);
}
- }
-
- // add to the extended security roles
- addExtendedSecurityRoles(nodeRef, readers, writers);
-
- if (applyToParents)
+ }
+ }
+
+ /**
+ * Get the IPR groups associated with a given node reference.
+ *
+ * Return null if none found.
+ *
+ * @param nodeRef node reference
+ * @return Pair where first is the read group and second if the write group, null if none found
+ */
+ private Pair getIPRGroups(NodeRef nodeRef)
+ {
+ Pair result = null;
+ String iprReaderGroup = null;
+ String iprWriterGroup = null;
+
+ // get all the set permissions
+ Set permissions = permissionService.getAllSetPermissions(nodeRef);
+ for (AccessPermission permission : permissions)
{
- // apply the extended readers up the file plan primary hierarchy
- NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef();
- if (parent != null &&
- filePlanService.isFilePlanComponent(parent))
+ // look for the presence of the reader group
+ if (permission.getAuthority().startsWith(GROUP_PREFIX + READER_GROUP_PREFIX))
{
- addExtendedSecurityImpl(parent, readers, null, applyToParents);
- addExtendedSecurityImpl(parent, writers, null, applyToParents);
+ iprReaderGroup = permission.getAuthority();
+ }
+ // look for the presence of the writer group
+ else if (permission.getAuthority().startsWith(GROUP_PREFIX + WRITER_GROUP_PREFIX))
+ {
+ iprWriterGroup = permission.getAuthority();
}
}
- }
-
- /**
- *
- * @param nodeRef
- * @param readers
- * @param writers
- */
- private void addExtendedSecurityRoles(NodeRef nodeRef, Set readers, Set writers)
- {
- NodeRef filePlan = filePlanService.getFilePlan(nodeRef);
-
- addExtendedSecurityRolesImpl(filePlan, readers, PROP_EXTENDED_READER_ROLE, FilePlanRoleService.ROLE_EXTENDED_READERS);
- addExtendedSecurityRolesImpl(filePlan, writers, PROP_EXTENDED_WRITER_ROLE, FilePlanRoleService.ROLE_EXTENDED_WRITERS);
- }
-
- /**
- *
- * @param filePlan
- * @param authorities
- * @param propertyName
- * @param roleName
- */
- @SuppressWarnings("unchecked")
- private void addExtendedSecurityRolesImpl(NodeRef filePlan, Set authorities, QName propertyName, String roleName)
- {
- if (authorities != null)
+
+ // assuming the are both present then return
+ if (iprReaderGroup != null && iprWriterGroup != null)
{
- // get the reference count
- Map referenceCountMap = (Map)nodeService.getProperty(filePlan, propertyName);
-
- // set of assigned authorities
- Set assignedAuthorities = new HashSet(authorities.size());
+ result = new Pair(iprReaderGroup, iprWriterGroup);
+ }
- for (String authority : authorities)
- {
- if ((!authority.equals(PermissionService.ALL_AUTHORITIES) &&
- !authority.equals(PermissionService.OWNER_AUTHORITY)) &&
- !AuthorityType.ROLE.equals(AuthorityType.getAuthorityType(authority)) &&
- (referenceCountMap == null || !referenceCountMap.containsKey(authority)))
- {
- // add the authority to the role
- filePlanRoleService.assignRoleToAuthority(filePlan, roleName, authority);
- assignedAuthorities.add(authority);
- }
- }
-
- // update the reference count
- nodeService.setProperty(filePlan, propertyName, (Serializable)addToMap(referenceCountMap, assignedAuthorities));
- }
+ return result;
}
-
+
/**
- *
- * @param map
- * @param keys
+ * Given a set of readers and writers find or create the appropriate IPR groups.
+ *
+ * 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.
+ *
+ * When no match is found the groups are created. Once created
+ *
+ * @param filePlan file plan
+ * @param readers authorities with read
+ * @param writers authorities with write
+ * @return Pair where first is the full name of the read group and
+ * second is the full name of the write group
+ */
+ private Pair createOrFindIPRGroups(Set readers, Set writers)
+ {
+ return new Pair(
+ createOrFindIPRGroup(READER_GROUP_PREFIX, readers),
+ createOrFindIPRGroup(WRITER_GROUP_PREFIX, writers));
+ }
+
+ /**
+ * Create or find an IPR group based on the provided prefix and authorities.
+ *
+ * @param groupPrefix group prefix
+ * @param authorities authorities
+ * @return String full group name
+ */
+ private String createOrFindIPRGroup(String groupPrefix, Set authorities)
+ {
+ String group = null;
+
+ // find group or determine what the next index is if no group exists or there is a clash
+ Pair groupResult = findIPRGroup(groupPrefix, authorities);
+
+ if (groupResult.getFirst() == null)
+ {
+ group = createIPRGroup(groupPrefix, authorities, groupResult.getSecond());
+ }
+ else
+ {
+ group = groupResult.getFirst();
+ }
+
+ return group;
+ }
+
+ /**
+ * Given a group name prefix and the authorities, finds the exact match existing group.
+ *
+ * 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 where first is the name of the found group, null if none found and second
+ * if the next available create index
+ */
+ private Pair findIPRGroup(String groupPrefix, Set authorities)
+ {
+ 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 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(iprGroup, nextGroupIndex);
+ }
+
+ /**
+ * Determines whether a group exactly matches a list of authorities.
+ *
+ * @param authorities list of authorities
+ * @param group group
* @return
*/
- private Map addToMap(Map map, Set keys)
+ private boolean isIPRGroupTrueMatch(String group, Set authorities)
+ {
+ Set contained = authorityService.getContainedAuthorities(null, group, true);
+ return contained.equals(authorities);
+ }
+
+ /**
+ * Get IPR group prefix short name.
+ *
+ * 'package' scope to help testing.
+ *
+ * @param prefix prefix
+ * @param authorities authorities
+ * @return String group prefix short name
+ */
+ /*package*/ String getIPRGroupPrefixShortName(String prefix, Set authorities)
{
- if (map == null)
+ StringBuilder builder = new StringBuilder(128)
+ .append(prefix)
+ .append(getAuthoritySetHashCode(authorities));
+
+ return builder.toString();
+ }
+
+ /**
+ * Get IPR group short name.
+ *
+ * Note this excludes the "GROUP_" prefix.
+ *
+ * '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 authorities, int index)
+ {
+ return getIPRGroupShortName(prefix, authorities, Integer.toString(index));
+ }
+
+ /**
+ * Get IPR group short name.
+ *
+ * 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 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 authorities)
+ {
+ int result = 0;
+ if (authorities != null && !authorities.isEmpty())
{
- // create map
- map = new HashMap(7);
+ result = StringUtils.join(authorities.toArray(), "").hashCode();
}
-
- for (String key : keys)
+ 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 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)
{
- if (!key.equals(PermissionService.ALL_AUTHORITIES))
+ for (String child : children)
{
- if (map.containsKey(key))
+ if (authorityService.authorityExists(child) &&
+ !PermissionService.ALL_AUTHORITIES.equals(child))
{
- // increment reference count
- Integer count = map.get(key);
- map.put(key, Integer.valueOf(count.intValue()+1));
- }
- else
- {
- // add key with initial count
- map.put(key, Integer.valueOf(1));
+ authorityService.addAuthority(group, child);
}
}
}
-
- 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)
+ * 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 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
- public void removeExtendedSecurity(NodeRef nodeRef, Set readers, Set writers)
+ public void remove(NodeRef nodeRef)
{
- removeExtendedSecurity(nodeRef, readers, writers, true);
- }
-
- /**
- * @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#removeExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set, boolean)
- */
- @Override
- public void removeExtendedSecurity(NodeRef nodeRef, Set readers, Setwriters, boolean applyToParents)
- {
- if (hasExtendedSecurity(nodeRef))
+ ParameterCheck.mandatory("nodeRef", nodeRef);
+
+ Pair 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
if (isRecord(nodeRef))
{
@@ -320,110 +562,85 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
for (ChildAssociationRef assoc : assocs)
{
NodeRef child = assoc.getChildRef();
- removeExtendedSecurityImpl(child, readers, writers);
- }
- }
-
- 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);
+ clearPermissions(child, iprGroups);
}
}
}
}
/**
- * Removes a set of readers and writers from a node reference.
- *
- * Removes the aspect and resets the property to null if all readers and writers are removed.
- *
+ * Clear the nodes IPR permissions
+ *
* @param nodeRef node reference
- * @param readers {@link Set} of readers
- * @param writers {@link Set} of writers
*/
- @SuppressWarnings("unchecked")
- private void removeExtendedSecurityImpl(NodeRef nodeRef, Set readers, Set writers)
+ private void clearPermissions(NodeRef nodeRef, Pair iprGroups)
{
- Map readersMap = (Map)nodeService.getProperty(nodeRef, PROP_READERS);
- nodeService.setProperty(nodeRef, PROP_READERS, (Serializable)removeFromMap(readersMap, readers));
-
- Map writersMap = (Map)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);
- }
+ // remove group permissions from node
+ permissionService.clearPermission(nodeRef, iprGroups.getFirst());
+ permissionService.clearPermission(nodeRef, iprGroups.getSecond());
+ }
+
+ /**
+ * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#getExtendedReaders(org.alfresco.service.cmr.repository.NodeRef)
+ */
+ @Override @Deprecated public Set getExtendedReaders(NodeRef nodeRef)
+ {
+ return getReaders(nodeRef);
+ }
+
+ /**
+ * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#getExtendedWriters(org.alfresco.service.cmr.repository.NodeRef)
+ */
+ @Override @Deprecated public Set getExtendedWriters(NodeRef nodeRef)
+ {
+ return getWriters(nodeRef);
+ }
+
+ /**
+ * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#addExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set)
+ */
+ @Override @Deprecated public void addExtendedSecurity(NodeRef nodeRef, Set readers, Set writers)
+ {
+ 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 readers, Set writers, boolean applyToParents)
+ {
+ 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 readers, Set writers)
+ {
+ remove(nodeRef);
}
/**
- * Helper method to remove items from map or reduce reference count
- *
- * @param map ref count map
- * @param keys keys
- * @return Map ref count map
+ * @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#removeExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set, boolean)
*/
- private Map removeFromMap(Map map, Set keys)
+ @Override @Deprecated public void removeExtendedSecurity(NodeRef nodeRef, Set readers, Setwriters, boolean applyToParents)
{
- if (map != null && keys != null && keys.size() != 0)
- {
- // 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;
+ remove(nodeRef);
}
/**
- * @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#removeAllExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, boolean)
*/
- @Override
- public void removeAllExtendedSecurity(NodeRef nodeRef)
+ @Override @Deprecated public void removeAllExtendedSecurity(NodeRef nodeRef, boolean applyToParents)
{
- removeAllExtendedSecurity(nodeRef, true);
- }
-
- /**
- * @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#removeAllExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, boolean)
- */
- @Override
- public void removeAllExtendedSecurity(NodeRef nodeRef, boolean applyToParents)
- {
- if (hasExtendedSecurity(nodeRef))
- {
- removeExtendedSecurity(nodeRef, getExtendedReaders(nodeRef), getExtendedWriters(nodeRef));
- }
+ remove(nodeRef);
}
}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/FilePlanPermissionServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/FilePlanPermissionServiceImpl.java
index 030fa5cd05..17f40991ad 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/FilePlanPermissionServiceImpl.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/security/FilePlanPermissionServiceImpl.java
@@ -18,8 +18,6 @@
*/
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.annotation.BehaviourKind.CLASS;
import static org.alfresco.repo.security.authentication.AuthenticationUtil.getSystemUserName;
@@ -374,13 +372,29 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
boolean inheritanceAllowed = isInheritanceAllowed(nodeRef, isParentNodeFilePlan);
getPermissionService().setInheritParentPermissions(nodeRef, inheritanceAllowed);
- // clear all existing permissions
+ Set keepPerms = new HashSet(5);
+ Set 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);
+ // re-add keep'er permissions
+ for (AccessPermission keeper : keepPerms)
+ {
+ setPermission(nodeRef, keeper.getAuthority(), keeper.getPermission());
+ }
+
if (!inheritanceAllowed)
{
- getPermissionService().setPermission(nodeRef, EXTENDED_READER, READ_RECORDS, true);
- getPermissionService().setPermission(nodeRef, EXTENDED_WRITER, FILING, true);
String adminRole = getAdminRole(nodeRef);
getPermissionService().setPermission(nodeRef, adminRole, RMPermissionModel.FILING, true);
}
@@ -426,9 +440,20 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
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)
{
- 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)));
}
/**
@@ -485,20 +510,14 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
for (AccessPermission recordPermission : origionalRecordPerms)
{
String permission = recordPermission.getPermission();
- String authority = recordPermission.getAuthority();
if ((RMPermissionModel.FILING.equals(permission) || RMPermissionModel.READ_RECORDS.equals(permission)) &&
- recordPermission.isSetDirectly() &&
- !ExtendedReaderDynamicAuthority.EXTENDED_READER.equals(authority) &&
- !ExtendedWriterDynamicAuthority.EXTENDED_WRITER.equals(authority))
+ recordPermission.isSetDirectly())
{
// then we can assume this is a permission we want to preserve
keepPerms.add(recordPermission);
}
}
- // clear all existing permissions and start again
- permissionService.deletePermissions(record);
-
// re-setup the records permissions
setupPermissions(destinationAssocRef.getParentRef(), record);
@@ -580,7 +599,7 @@ public class FilePlanPermissionServiceImpl extends ServiceBaseImpl
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);
}
/**
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java
index a148fd3016..880ce2bfb8 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/version/RecordableVersionServiceImpl.java
@@ -25,7 +25,6 @@ import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -47,12 +46,12 @@ import org.alfresco.repo.version.VersionModel;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
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.Version;
import org.alfresco.service.cmr.version.VersionHistory;
import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.service.namespace.QName;
+import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyMap;
import org.apache.commons.logging.Log;
@@ -118,9 +117,6 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
/** extended security service */
private ExtendedSecurityService extendedSecurityService;
-
- /** ownable service */
- private OwnableService ownableService;
/**
* @param filePlanService file plan service
@@ -185,14 +181,6 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
{
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)
@@ -635,13 +623,8 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
{
public NodeRef doWork() throws Exception
{
- // get the documents readers
- Long aclId = nodeService.getNodeAclId(nodeRef);
- Set readers = extendedPermissionService.getReaders(aclId);
- Set writers = extendedPermissionService.getWriters(aclId);
-
- // add the current owner to the list of extended writers
- String owner = ownableService.getOwner(nodeRef);
+ // get the documents readers and writers
+ Pair, Set> readersAndWriters = extendedPermissionService.getReadersAndWriters(nodeRef);
// grab the frozen state
NodeRef currentFrozenState = currentVersion.getFrozenStateNodeRef();
@@ -681,13 +664,7 @@ public class RecordableVersionServiceImpl extends Version2ServiceImpl
linkToPreviousVersionRecord(nodeRef, record);
// set the extended security
- Set combinedWriters = new HashSet(writers);
- if (owner != null && !owner.isEmpty() && !owner.equals(OwnableService.NO_OWNER))
- {
- combinedWriters.add(owner);
- }
- combinedWriters.add(authenticationUtil.getFullyAuthenticatedUser());
- extendedSecurityService.addExtendedSecurity(record, readers, combinedWriters);
+ extendedSecurityService.set(record, readersAndWriters);
return record;
}
diff --git a/rm-server/source/java/org/alfresco/repo/security/permissions/impl/ExtendedPermissionService.java b/rm-server/source/java/org/alfresco/repo/security/permissions/impl/ExtendedPermissionService.java
index 779301e83d..6fcce8196d 100644
--- a/rm-server/source/java/org/alfresco/repo/security/permissions/impl/ExtendedPermissionService.java
+++ b/rm-server/source/java/org/alfresco/repo/security/permissions/impl/ExtendedPermissionService.java
@@ -20,7 +20,9 @@ package org.alfresco.repo.security.permissions.impl;
import java.util.Set;
+import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.util.Pair;
/**
* Extended Permission Service Interface used in RM.
@@ -31,4 +33,18 @@ import org.alfresco.service.cmr.security.PermissionService;
public interface ExtendedPermissionService extends PermissionService
{
Set getWriters(Long aclId);
+
+ /**
+ * Get the readers and writers for a given node.
+ *
+ * The writers list includes the owner for the node.
+ *
+ * @param nodeRef node reference
+ * @return Pair, Set> 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> getReadersAndWriters(NodeRef nodeRef);
}
diff --git a/rm-server/source/java/org/alfresco/repo/security/permissions/impl/RMPermissionServiceImpl.java b/rm-server/source/java/org/alfresco/repo/security/permissions/impl/RMPermissionServiceImpl.java
index e01c1be439..c2b7e30cbb 100644
--- a/rm-server/source/java/org/alfresco/repo/security/permissions/impl/RMPermissionServiceImpl.java
+++ b/rm-server/source/java/org/alfresco/repo/security/permissions/impl/RMPermissionServiceImpl.java
@@ -29,16 +29,17 @@ 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.security.ExtendedReaderDynamicAuthority;
-import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.security.permissions.AccessControlEntry;
import org.alfresco.repo.security.permissions.AccessControlList;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityType;
+import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.util.Pair;
import org.alfresco.util.PropertyCheck;
+import org.apache.commons.lang.StringUtils;
import org.springframework.context.ApplicationEvent;
/**
@@ -303,13 +304,17 @@ public class RMPermissionServiceImpl extends PermissionServiceImpl
final String adminRole = getAdminRole(nodeRef);
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);
}
+ /**
+ * 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)
{
String adminRole = null;
@@ -320,4 +325,28 @@ public class RMPermissionServiceImpl extends PermissionServiceImpl
}
return adminRole;
}
+
+ /**
+ * @see org.alfresco.repo.security.permissions.impl.ExtendedPermissionService#getReadersAndWriters(org.alfresco.service.cmr.repository.NodeRef)
+ */
+ @Override
+ public Pair, Set> getReadersAndWriters(NodeRef nodeRef)
+ {
+ // get the documents readers
+ Long aclId = nodeService.getNodeAclId(nodeRef);
+ Set readers = getReaders(aclId);
+ Set writers = getWriters(aclId);
+
+ // add the current owner to the list of extended writers
+ Set modifiedWrtiers = new HashSet(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> (readers, modifiedWrtiers);
+ }
}
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1429Test.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1429Test.java
index 96e835729d..f35e2f10e9 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1429Test.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1429Test.java
@@ -35,14 +35,14 @@ public class RM1429Test extends DeleteHoldTest
{
public void testDeleteHoldWithoutPermissionsOnChildren()
{
- // Create the test hold
- final NodeRef hold = createAndCheckHold();
-
- doTestInTransaction(new Test()
+ final NodeRef hold = doTestInTransaction(new Test()
{
@Override
- public Void run()
+ public NodeRef run()
{
+ // Create the test hold
+ NodeRef hold = createAndCheckHold();
+
// Add the user to the RM Manager role
filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_RECORDS_MANAGER, userName);
@@ -55,7 +55,7 @@ public class RM1429Test extends DeleteHoldTest
// Add record folder to the hold
holdService.addToHold(hold, rmFolder);
- return null;
+ return hold;
}
});
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1463Test.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1463Test.java
index 074eb27e83..517b316ab1 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1463Test.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1463Test.java
@@ -35,14 +35,14 @@ public class RM1463Test extends DeleteHoldTest
{
public void testAddRecordFolderToHoldWithoutFilingPermissionOnRecordFolder()
{
- // Create hold
- final NodeRef hold = createAndCheckHold();
-
- doTestInTransaction(new Test()
+ final NodeRef hold = doTestInTransaction(new Test()
{
@Override
- public Void run()
+ public NodeRef run()
{
+ // Create hold
+ NodeRef hold = createAndCheckHold();
+
// Add the user to the RM Manager role
filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_RECORDS_MANAGER, userName);
@@ -52,7 +52,7 @@ public class RM1463Test extends DeleteHoldTest
// Give the user only read permissions on the record folder
permissionService.setPermission(rmFolder, userName, RMPermissionModel.READ_RECORDS, true);
- return null;
+ return hold;
}
});
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1464Test.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1464Test.java
index 5a009bb620..83ef6cbf6d 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1464Test.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM1464Test.java
@@ -35,14 +35,14 @@ public class RM1464Test extends DeleteHoldTest
{
public void testAddRecordFolderToHoldWithoutFilingPermissionOnHold()
{
- // Create hold
- final NodeRef hold = createAndCheckHold();
-
- doTestInTransaction(new Test()
+ final NodeRef hold = doTestInTransaction(new Test()
{
@Override
- public Void run()
+ public NodeRef run()
{
+ // Create hold
+ NodeRef hold = createAndCheckHold();
+
// Add the user to the RM Manager role
filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_RECORDS_MANAGER, userName);
@@ -52,7 +52,7 @@ public class RM1464Test extends DeleteHoldTest
// Give the user filing permissions on the record folder
permissionService.setPermission(rmFolder, userName, RMPermissionModel.FILING, true);
- return null;
+ return hold;
}
});
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CreateInplaceRecordTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CreateInplaceRecordTest.java
new file mode 100644
index 0000000000..0394e67af0
--- /dev/null
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/CreateInplaceRecordTest.java
@@ -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 .
+ * #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()
+ {
+ 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()
+ {
+ 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()
+ {
+ 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()
+ {
+ 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()
+ {
+ 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()
+ {
+ 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);
+
+ }
+ });
+ }
+}
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/InplaceRecordPermissionTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/InplaceRecordPermissionTest.java
new file mode 100644
index 0000000000..b972d7823a
--- /dev/null
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/InplaceRecordPermissionTest.java
@@ -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 .
+ * #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 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 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));
+ }
+}
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/MoveInplaceRecordTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/MoveInplaceRecordTest.java
index 9c05652660..d647def3e5 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/MoveInplaceRecordTest.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/record/MoveInplaceRecordTest.java
@@ -60,6 +60,9 @@ public class MoveInplaceRecordTest extends BaseRMTestCase
// Extended Readers/Writers
private Set extendedReadersBeforeMove;
private Set extendedWritersBeforeMove;
+
+ // primary parent of record
+ private NodeRef primaryParentBeforeMove;
public void given()
{
@@ -84,8 +87,14 @@ public class MoveInplaceRecordTest extends BaseRMTestCase
// Check that the document is a record now
assertTrue(recordService.isRecord(dmDocument));
- extendedReadersBeforeMove = extendedSecurityService.getExtendedReaders(dmDocument);
- extendedWritersBeforeMove = extendedSecurityService.getExtendedWriters(dmDocument);
+ extendedReadersBeforeMove = extendedSecurityService.getReaders(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()
@@ -105,15 +114,27 @@ public class MoveInplaceRecordTest extends BaseRMTestCase
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
assertEquals(0, nodeService.getChildAssocs(dmFolder).size());
List destinationFolderChildAssocs = nodeService.getChildAssocs(destinationDmFolder);
assertEquals(1, destinationFolderChildAssocs.size());
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
- Set extendedReadersAfterMove = extendedSecurityService.getExtendedReaders(dmDocument);
- Set extendedWritersAfterMove = extendedSecurityService.getExtendedWriters(dmDocument);
+ Set extendedReadersAfterMove = extendedSecurityService.getReaders(dmDocument);
+ Set extendedWritersAfterMove = extendedSecurityService.getWriters(dmDocument);
assertEquals(extendedReadersBeforeMove.size(), extendedReadersAfterMove.size());
assertEquals(extendedWritersBeforeMove.size(), extendedWritersAfterMove.size());
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/FileReportActionTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/FileReportActionTest.java
index 5b0c8a11b0..0a0573aae7 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/FileReportActionTest.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/FileReportActionTest.java
@@ -21,6 +21,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.test.util.BaseRMTestCase;
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.repository.NodeRef;
import org.apache.commons.lang.StringUtils;
@@ -53,6 +54,8 @@ public class FileReportActionTest extends BaseRMTestCase
private void fileReport(final String mimeType)
{
+ AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
+
// create record folder
final NodeRef recordFolder = recordFolderService.createRecordFolder(rmContainer, GUID.generate());
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/FileToActionTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/FileToActionTest.java
index f1d3c9d8a9..24c26bd7ad 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/FileToActionTest.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/FileToActionTest.java
@@ -29,6 +29,7 @@ import org.alfresco.module.org_alfresco_module_rm.action.impl.FileToAction;
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.test.util.BaseRMTestCase;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus;
@@ -109,16 +110,27 @@ public class FileToActionTest extends BaseRMTestCase
// create record from document
recordService.createRecord(filePlan, dmDocument);
- // check things have gone according to plan
- assertTrue(recordService.isRecord(dmDocument));
- assertFalse(recordService.isFiled(dmDocument));
-
- // is the unfiled container the primary parent of the filed record
- NodeRef parent = nodeService.getPrimaryParent(dmDocument).getParentRef();
- assertEquals(filePlanService.getUnfiledContainer(filePlan), parent);
-
return null;
}
+
+ @Override
+ public void test(Void result) throws Exception
+ {
+ AuthenticationUtil.runAs(() ->
+ {
+ // check things have gone according to plan
+ assertTrue(recordService.isRecord(dmDocument));
+ assertFalse(recordService.isFiled(dmDocument));
+
+ // is the unfiled container the primary parent of the filed record
+ NodeRef parent = nodeService.getPrimaryParent(dmDocument).getParentRef();
+ assertEquals(filePlanService.getUnfiledContainer(filePlan), parent);
+
+ return null;
+ },
+ AuthenticationUtil.getAdminUserName());
+ }
+
}, dmCollaborator);
}
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/RejectActionTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/RejectActionTest.java
index 9b84cd3876..adee075ed1 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/RejectActionTest.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/action/RejectActionTest.java
@@ -104,7 +104,8 @@ public class RejectActionTest extends BaseRMTestCase
assertTrue(nodeService.getParentAssocs(dmDocument).size() == 1);
// The extended reader information should be removed
- assertNull(extendedSecurityService.getExtendedReaders(dmDocument));
+ assertFalse(extendedSecurityService.hasExtendedSecurity(dmDocument));
+ assertTrue(extendedSecurityService.getReaders(dmDocument).isEmpty());
return null;
}
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/ExtendedSecurityServiceImplTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/ExtendedSecurityServiceImplTest.java
index 324b0ce759..6bf3110943 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/ExtendedSecurityServiceImplTest.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/ExtendedSecurityServiceImplTest.java
@@ -1,26 +1,33 @@
/*
- * Copyright (C) 2005-2014 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
+it st * #%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 .
+ * #L%
*/
+
package org.alfresco.module.org_alfresco_module_rm.test.legacy.service;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
@@ -92,76 +99,29 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
assertFalse(extendedSecurityService.hasExtendedSecurity(rmFolder));
assertFalse(extendedSecurityService.hasExtendedSecurity(record));
- assertNull(extendedSecurityService.getExtendedReaders(record));
- assertNull(extendedSecurityService.getExtendedWriters(record));
+ assertTrue(extendedSecurityService.getReaders(record).isEmpty());
+ assertTrue(extendedSecurityService.getWriters(record).isEmpty());
Set extendedReaders = new HashSet(2);
extendedReaders.add(monkey);
extendedReaders.add(elephant);
- extendedSecurityService.addExtendedSecurity(record, extendedReaders, null);
-
- Map testMap = new HashMap(2);
- testMap.put(monkey, Integer.valueOf(1));
- testMap.put(elephant, Integer.valueOf(1));
-
- checkExtendedReaders(filePlan, testMap);
- checkExtendedReaders(rmContainer, testMap);
- checkExtendedReaders(rmFolder, testMap);
- checkExtendedReaders(record, testMap);
+ extendedSecurityService.set(record, extendedReaders, null);
+ checkExtendedReaders(record, extendedReaders);
Set extendedReadersToo = new HashSet(2);
extendedReadersToo.add(monkey);
extendedReadersToo.add(snake);
- extendedSecurityService.addExtendedSecurity(recordToo, extendedReadersToo, null);
+ extendedSecurityService.set(recordToo, extendedReadersToo, null);
+ checkExtendedReaders(recordToo, extendedReadersToo);
- Map testMapToo = new HashMap(2);
- testMapToo.put(monkey, Integer.valueOf(1));
- testMapToo.put(snake, Integer.valueOf(1));
-
- Map testMapThree = new HashMap(3);
- testMapThree.put(monkey, Integer.valueOf(2));
- testMapThree.put(elephant, Integer.valueOf(1));
- testMapThree.put(snake, Integer.valueOf(1));
-
- checkExtendedReaders(filePlan, testMapThree);
- checkExtendedReaders(rmContainer, testMapThree);
- checkExtendedReaders(rmFolder, testMapThree);
- checkExtendedReaders(recordToo, testMapToo);
-
- // test remove (with no parent inheritance)
-
- Set removeMap1 = new HashSet(2);
- removeMap1.add(elephant);
- removeMap1.add(monkey);
-
- extendedSecurityService.removeExtendedSecurity(rmFolder, removeMap1, null, false);
-
- Map testMapFour = new HashMap(2);
- testMapFour.put(monkey, Integer.valueOf(1));
- testMapFour.put(snake, Integer.valueOf(1));
-
- checkExtendedReaders(filePlan, testMapThree);
- checkExtendedReaders(rmContainer, testMapThree);
- checkExtendedReaders(rmFolder, testMapFour);
- checkExtendedReaders(recordToo, testMapToo);
-
- // test remove (apply to parents)
-
- Set removeMap2 = new HashSet(1);
- removeMap2.add(snake);
-
- extendedSecurityService.removeExtendedSecurity(recordToo, removeMap2, null, true);
-
- testMapThree.remove(snake);
- testMapFour.remove(snake);
- testMapToo.remove(snake);
-
- checkExtendedReaders(filePlan, testMapThree);
- checkExtendedReaders(rmContainer, testMapThree);
- checkExtendedReaders(rmFolder, testMapFour);
- checkExtendedReaders(recordToo, testMapToo);
+ // test remove
+ extendedSecurityService.remove(recordToo);
+
+ assertFalse(extendedSecurityService.hasExtendedSecurity(recordToo));
+ assertTrue(extendedSecurityService.getReaders(recordToo).isEmpty());
+ assertTrue(extendedSecurityService.getWriters(recordToo).isEmpty());
return null;
}
@@ -175,12 +135,12 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
doTestInTransaction(new Test()
{
- Map testMap = new HashMap(2);
+ Set extendedReaders = new HashSet(2);;
public Void run() throws Exception
{
- testMap.put(monkey, Integer.valueOf(1));
- testMap.put(elephant, Integer.valueOf(1));
+ extendedReaders.add(monkey);
+ extendedReaders.add(elephant);
assertFalse(extendedSecurityService.hasExtendedSecurity(filePlan));
assertFalse(extendedSecurityService.hasExtendedSecurity(rmContainer));
@@ -189,18 +149,11 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordCategory));
assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordFolder));
- assertNull(extendedSecurityService.getExtendedReaders(record));
+ assertTrue(extendedSecurityService.getReaders(record).isEmpty());
- Set extendedReaders = new HashSet(2);
- extendedReaders.add(monkey);
- extendedReaders.add(elephant);
+ extendedSecurityService.set(record, extendedReaders, null);
- extendedSecurityService.addExtendedSecurity(record, extendedReaders, null);
-
- checkExtendedReaders(filePlan, testMap);
- checkExtendedReaders(rmContainer, testMap);
- checkExtendedReaders(rmFolder, testMap);
- checkExtendedReaders(record, testMap);
+ checkExtendedReaders(record, extendedReaders);
assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordCategory));
assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordFolder));
@@ -212,36 +165,21 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
@Override
public void test(Void result) throws Exception
{
- checkExtendedReaders(filePlan, testMap);
- assertFalse(extendedSecurityService.hasExtendedSecurity(rmContainer));
- // assertEquals(0, extendedSecurityService.getExtendedReaders(rmFolder).size());
- checkExtendedReaders(moveRecordCategory, testMap);
- checkExtendedReaders(moveRecordFolder, testMap);
- checkExtendedReaders(record, testMap);
+ checkExtendedReaders(record, extendedReaders);
}
});
}
-
- @SuppressWarnings("unchecked")
- private void checkExtendedReaders(NodeRef nodeRef, Map testMap)
+ /**
+ * Check extended readers helper method
+ */
+ private void checkExtendedReaders(NodeRef nodeRef, Set testReaders)
{
assertTrue(extendedSecurityService.hasExtendedSecurity(nodeRef));
- Map readersMap = (Map)nodeService.getProperty(nodeRef, PROP_READERS);
- assertNotNull(readersMap);
- assertEquals(testMap.size(), readersMap.size());
-
- for (Map.Entry entry: testMap.entrySet())
- {
- assertTrue(readersMap.containsKey(entry.getKey()));
- assertEquals(entry.getKey(), entry.getValue(), readersMap.get(entry.getKey()));
-
- }
-
- Set readers = extendedSecurityService.getExtendedReaders(nodeRef);
+ Set readers = extendedSecurityService.getReaders(nodeRef);
assertNotNull(readers);
- assertEquals(testMap.size(), readers.size());
+ assertEquals(testReaders, readers);
}
public void testDifferentUsersDifferentPermissions()
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/FilePlanPermissionServiceImplTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/FilePlanPermissionServiceImplTest.java
index eea15bc001..365cf1db86 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/FilePlanPermissionServiceImplTest.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/FilePlanPermissionServiceImplTest.java
@@ -24,8 +24,6 @@ import java.util.Set;
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.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.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -1232,10 +1230,6 @@ public class FilePlanPermissionServiceImplTest extends BaseRMTestCase
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());
assertTrue(accessPermissions.containsKey(adminRole));
assertEquals(RMPermissionModel.FILING, accessPermissions.get(adminRole));
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordServiceImplTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordServiceImplTest.java
index 14f5ffa379..36304ac076 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordServiceImplTest.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordServiceImplTest.java
@@ -30,8 +30,6 @@ 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.role.FilePlanRoleService;
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.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
@@ -174,22 +172,13 @@ public class RecordServiceImplTest extends BaseRMTestCase
public void testExtendedWriters() throws Exception
{
- final ExtendedReaderDynamicAuthority readerDy = (ExtendedReaderDynamicAuthority)applicationContext.getBean("extendedReaderDynamicAuthority");
- final ExtendedWriterDynamicAuthority writerDy = (ExtendedWriterDynamicAuthority)applicationContext.getBean("extendedWriterDynamicAuthority");
-
doTestInTransaction(new Test()
{
@Override
public Void run()
{
- assertNull(extendedSecurityService.getExtendedReaders(recordOne));
- assertNull(extendedSecurityService.getExtendedWriters(recordOne));
-
- assertFalse(readerDy.hasAuthority(recordOne, dmCollaborator));
- assertFalse(writerDy.hasAuthority(recordOne, dmCollaborator));
-
- assertFalse(readerDy.hasAuthority(filePlan, dmCollaborator));
- assertFalse(writerDy.hasAuthority(filePlan, dmCollaborator));
+ assertTrue(extendedSecurityService.getReaders(recordOne).isEmpty());
+ assertTrue(extendedSecurityService.getWriters(recordOne).isEmpty());
return null;
}
@@ -202,16 +191,9 @@ public class RecordServiceImplTest extends BaseRMTestCase
{
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(recordOne, RMPermissionModel.READ_RECORDS));
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.EDIT_NON_RECORD_METADATA));
- assertFalse(readerDy.hasAuthority(filePlan, dmCollaborator));
- assertFalse(writerDy.hasAuthority(filePlan, dmCollaborator));
-
return null;
}
}, dmCollaborator);
@@ -223,10 +205,10 @@ public class RecordServiceImplTest extends BaseRMTestCase
{
Set writers = new HashSet(1);
writers.add(dmCollaborator);
- extendedSecurityService.addExtendedSecurity(recordOne, null, writers);
+ extendedSecurityService.set(recordOne, null, writers);
- assertNull(extendedSecurityService.getExtendedReaders(recordOne));
- assertFalse(extendedSecurityService.getExtendedWriters(recordOne).isEmpty());
+ assertTrue(extendedSecurityService.getReaders(recordOne).isEmpty());
+ assertFalse(extendedSecurityService.getWriters(recordOne).isEmpty());
return null;
}
@@ -240,9 +222,7 @@ public class RecordServiceImplTest extends BaseRMTestCase
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(recordOne, RMPermissionModel.READ_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(recordOne, RMPermissionModel.FILING));
- assertFalse(readerDy.hasAuthority(recordOne, dmCollaborator));
- assertTrue(writerDy.hasAuthority(recordOne, dmCollaborator));
-
+ // ALLOWED, becuase users have been added to the in-place roles
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan, RMPermissionModel.VIEW_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan, RMPermissionModel.EDIT_NON_RECORD_METADATA));
@@ -304,19 +284,18 @@ public class RecordServiceImplTest extends BaseRMTestCase
public void test(Void result)
{
- checkPermissions(READ_RECORDS, AccessStatus.ALLOWED, // file
- // plan
- AccessStatus.ALLOWED, // unfiled container
+ checkPermissions(READ_RECORDS,
+ AccessStatus.DENIED, // file
+ AccessStatus.DENIED, // unfiled container
AccessStatus.DENIED, // record category
AccessStatus.DENIED, // record folder
AccessStatus.ALLOWED); // doc/record
- permissionReport();
-
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan,
RMPermissionModel.VIEW_RECORDS));
- checkPermissions(FILING, AccessStatus.DENIED, // file plan
+ checkPermissions(FILING,
+ AccessStatus.DENIED, // file plan
AccessStatus.DENIED, // unfiled container
AccessStatus.DENIED, // record category
AccessStatus.DENIED, // record folder
@@ -362,9 +341,8 @@ public class RecordServiceImplTest extends BaseRMTestCase
@Override
public Void run()
{
- checkPermissions(READ_RECORDS, AccessStatus.ALLOWED, // file
- // plan
- AccessStatus.ALLOWED, // unfiled container
+ checkPermissions(READ_RECORDS, AccessStatus.DENIED, // file plan
+ AccessStatus.DENIED, // unfiled container
AccessStatus.DENIED, // record category
AccessStatus.DENIED, // record folder
AccessStatus.ALLOWED); // doc/record
@@ -394,38 +372,6 @@ public class RecordServiceImplTest extends BaseRMTestCase
}, dmConsumer);
}
- private void permissionReport()
- {
- Set writers = extendedSecurityService.getExtendedWriters(dmDocument);
- for (String writer : writers)
- {
- System.out.println("writer: " + writer);
- }
-
- System.out.println("Users assigned to extended writers role:");
- Set assignedUsers = filePlanRoleService.getUsersAssignedToRole(filePlan, FilePlanRoleService.ROLE_EXTENDED_WRITERS);
- for (String assignedUser : assignedUsers)
- {
- System.out.println(" ... " + assignedUser);
- }
-
- Set perms = permissionService.getAllSetPermissions(filePlan);
- for (AccessPermission perm : perms)
- {
- if (perm.getPermission().contains(RMPermissionModel.EDIT_NON_RECORD_METADATA))
- {
- System.out.println(" ... " + perm.getAuthority() + " - " + perm.getPermission() + " - " + perm.getAccessStatus().toString());
- }
- }
- for (AccessPermission perm : perms)
- {
- if (perm.getPermission().contains(RMPermissionModel.VIEW_RECORDS))
- {
- System.out.println(" ... " + perm.getAuthority() + " - " + perm.getPermission() + " - " + perm.getAccessStatus().toString());
- }
- }
- }
-
public void testCreateRecordNoLink() throws Exception
{
// show that users without WRITE can not create a record from a document
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java
index ab2da29b56..d549b1ffa6 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java
@@ -262,6 +262,8 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase
/** collaboration site users */
protected String dmConsumer;
protected NodeRef dmConsumerNodeRef;
+ protected String dmContributor;
+ protected NodeRef dmContributorNodeRef;
protected String dmCollaborator;
protected NodeRef dmCollaboratorNodeRef;
@@ -412,11 +414,12 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase
@Override
public Object execute() throws Throwable
{
- // As system user
- AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
-
// Do the tear down
- tearDownImpl();
+ AuthenticationUtil.runAsSystem(() ->
+ {
+ tearDownImpl();
+ return null;
+ });
return null;
}
@@ -591,16 +594,21 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase
protected void setupTestUsers(final NodeRef filePlan)
{
- retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback