From 23206d29a31b8cb14d735151e47412454e252dbe Mon Sep 17 00:00:00 2001 From: Roy Wetherall Date: Mon, 18 Feb 2013 23:50:21 +0000 Subject: [PATCH] RM: Global RM admin user added * this allows code to be 'runAsRMAdmin' .. rather than having to use System (remember 'admin' isn't nessesarily an rm admin) * will give us the option to run rm rules as rmAdmin (this may be the default case for the time being and later part of the configuration of the rule) * will also allow us to add RM admin level security to methods (for example can only create a role if you are an rm admin) * rmAdmin user has global RM admin rights to all file plans (when we go to multi-file plan support) * rm user bootstrapped via module 'patch' .. this will execute on existing V2.1 db's * filePlanRoleService unit test (was missing! .. my bad!) * relates to RM-596 (this rule needs to be executed as the rm admin) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@46749 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../alfresco-global.properties | 5 +- .../rm-patch-context.xml | 15 ++ .../patch/RMv2ModelPatch.java | 2 +- .../patch/RMv2RMAdminUserPatch.java | 124 ++++++++++++ .../role/FilePlanRoleService.java | 3 + .../role/FilePlanRoleServiceImpl.java | 14 ++ .../service/FilePlanRoleServiceImplTest.java | 181 ++++++++++++++++++ .../test/util/BaseRMTestCase.java | 16 ++ 8 files changed, 358 insertions(+), 2 deletions(-) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2RMAdminUserPatch.java create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/FilePlanRoleServiceImplTest.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties b/rm-server/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties index d1f174fa68..1c7d41af91 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/alfresco-global.properties @@ -21,4 +21,7 @@ audit.rm.enabled=true # # Extended permission service cache sizing # -cache.writersSharedCache.maxItems=10000 \ No newline at end of file +cache.writersSharedCache.maxItems=10000 + +# Global RM admin default pwd +rm.rmadmin.pwd=rmadmin \ No newline at end of file diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-patch-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-patch-context.xml index 10212b6e9d..e76c17d6c4 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-patch-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-patch-context.xml @@ -76,5 +76,20 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2ModelPatch.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2ModelPatch.java index 545d846d92..1db2d4fd45 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2ModelPatch.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2ModelPatch.java @@ -43,7 +43,7 @@ public class RMv2ModelPatch extends AbstractModuleComponent implements BeanNameAware, RecordsManagementModel, DOD5015Model { /** Logger */ - private static Log logger = LogFactory.getLog(NotificationTemplatePatch.class); + private static Log logger = LogFactory.getLog(RMv2ModelPatch.class); private static long BATCH_SIZE = 100000L; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2RMAdminUserPatch.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2RMAdminUserPatch.java new file mode 100644 index 0000000000..30fb517c94 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/RMv2RMAdminUserPatch.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.patch; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.RecordsManagementService; +import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService; +import org.alfresco.repo.module.AbstractModuleComponent; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.MutableAuthenticationService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.QName; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.BeanNameAware; + +/** + * RM v2.1: RM admin user patch + * + * @author Roy Wetherall + */ +public class RMv2RMAdminUserPatch extends AbstractModuleComponent implements BeanNameAware +{ + /** Logger */ + private static Log logger = LogFactory.getLog(RMv2RMAdminUserPatch.class); + + private String password = "rmadmin"; + + private MutableAuthenticationService authenticationService; + + private PersonService personService; + + private RecordsManagementService recordsManagementService; + + private FilePlanRoleService filePlanRoleService; + + public void setPassword(String password) + { + this.password = password; + } + + public void setPersonService(PersonService personService) + { + this.personService = personService; + } + + public void setAuthenticationService(MutableAuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + public void setRecordsManagementService(RecordsManagementService recordsManagementService) + { + this.recordsManagementService = recordsManagementService; + } + + public void setFilePlanRoleService(FilePlanRoleService filePlanRoleService) + { + this.filePlanRoleService = filePlanRoleService; + } + + /** + * @see org.alfresco.repo.module.AbstractModuleComponent#executeInternal() + */ + @Override + protected void executeInternal() throws Throwable + { + if (logger.isDebugEnabled() == true) + { + logger.debug("RM Module RMv2RMAdminUserPatch ..."); + } + + if (authenticationService.authenticationExists(FilePlanRoleService.RM_ADMIN_USER) == false) + { + if (logger.isDebugEnabled() == true) + { + logger.debug(" ... creating RM Admin user"); + } + + authenticationService.createAuthentication(FilePlanRoleService.RM_ADMIN_USER, password.toCharArray()); + Map properties = new HashMap(); + properties.put(ContentModel.PROP_USERNAME, FilePlanRoleService.RM_ADMIN_USER); + personService.createPerson(properties); + + if (logger.isDebugEnabled() == true) + { + logger.debug(" ... assigning RM Admin user to file plans"); + } + + List filePlans = recordsManagementService.getFilePlans(); + for (NodeRef filePlan : filePlans) + { + filePlanRoleService.assignRoleToAuthority(filePlan, FilePlanRoleService.ROLE_ADMIN, FilePlanRoleService.RM_ADMIN_USER); + } + + if (logger.isDebugEnabled() == true) + { + logger.debug(" ... RMv2RMAdminUserPatch complete"); + } + } + + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/role/FilePlanRoleService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/role/FilePlanRoleService.java index afb260d62a..5649abc597 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/role/FilePlanRoleService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/role/FilePlanRoleService.java @@ -31,6 +31,9 @@ import org.alfresco.service.cmr.repository.NodeRef; */ public interface FilePlanRoleService { + /** Default rm admin user */ + public static final String RM_ADMIN_USER = "rmadmin"; + /** Default role names */ public static final String ROLE_USER = "User"; public static final String ROLE_POWER_USER = "PowerUser"; 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 0336be3606..ad07d9a4af 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 @@ -332,6 +332,9 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService, // Add the creating user to the administration group String user = AuthenticationUtil.getFullyAuthenticatedUser(); authorityService.addAuthority(role.getRoleGroupName(), user); + + // add the dynamic admin authority + authorityService.addAuthority(role.getRoleGroupName(), FilePlanRoleService.RM_ADMIN_USER); } } } @@ -619,6 +622,11 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService, { public Role doWork() throws Exception { + if (existsRole(rmRootNode, role) == false) + { + throw new AlfrescoRuntimeException("Unable to update role " + role + ", because it does not exist."); + } + String roleAuthority = authorityService.getName(AuthorityType.GROUP, getFullRoleName(role, rmRootNode)); // Reset the role display name @@ -646,6 +654,12 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService, */ public void deleteRole(final NodeRef rmRootNode, final String role) { + // ensure that we are not trying to delete the admin role + if (ROLE_ADMIN.equals(role) == true) + { + throw new AlfrescoRuntimeException("Can not delete the records management administration role."); + } + AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { public Boolean doWork() throws Exception diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/FilePlanRoleServiceImplTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/FilePlanRoleServiceImplTest.java new file mode 100644 index 0000000000..92a4c6cb1f --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/service/FilePlanRoleServiceImplTest.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2005-2013 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.test.service; + +import java.util.HashSet; +import java.util.Set; + +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.Role; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.service.cmr.security.AuthorityType; + +/** + * File plan role service unit test + * + * @author Roy Wetherall + * @since 2.1 + */ +public class FilePlanRoleServiceImplTest extends BaseRMTestCase +{ + @Override + protected boolean isUserTest() + { + return true; + } + + public void testGetAllRolesContainerGroup() throws Exception + { + doTestInTransaction(new Test() + { + public Void run() + { + String allRolesGroup = filePlanRoleService.getAllRolesContainerGroup(filePlan); + assertNotNull(allRolesGroup); + + Set allRoles = authorityService.getContainedAuthorities(AuthorityType.GROUP, allRolesGroup, true); + assertNotNull(allRoles); + assertTrue(allRoles.contains(filePlanRoleService.getRole(filePlan, ROLE_NAME_POWER_USER).getRoleGroupName())); + + return null; + } + }); + } + + public void testGetRoles() throws Exception + { + doTestInTransaction(new Test() + { + public Void run() + { + Set roles = filePlanRoleService.getRoles(filePlan); + assertNotNull(roles); + assertTrue(roles.size() != 0); + + return null; + } + }); + } + + public void testRolesByUser() throws Exception + { + doTestInTransaction(new Test() + { + public Void run() + { + Set roles = filePlanRoleService.getRolesByUser(filePlan, rmUserName); + assertNotNull(roles); + assertEquals(1, roles.size()); + + return null; + } + }); + } + + public void testGetRole() throws Exception + { + doTestInTransaction(new Test() + { + public Void run() + { + Role role = filePlanRoleService.getRole(filePlan, ROLE_NAME_POWER_USER); + assertNotNull(role); + assertEquals(ROLE_NAME_POWER_USER, role.getName()); + + role = filePlanRoleService.getRole(filePlan, "donkey"); + assertNull(role); + + return null; + } + }); + } + + public void testExistsRole() throws Exception + { + doTestInTransaction(new Test() + { + public Void run() + { + assertTrue(filePlanRoleService.existsRole(filePlan, ROLE_NAME_POWER_USER)); + assertFalse(filePlanRoleService.existsRole(filePlan, "donkey")); + + return null; + } + }); + } + + public void testCreateUpdateDeleteRole() throws Exception + { + doTestInTransaction(new Test() + { + public Void run() + { + assertFalse(filePlanRoleService.existsRole(filePlan, "Michelle Holt")); + + Set caps = new HashSet(2); + caps.add(capabilityService.getCapability(RMPermissionModel.ACCESS_AUDIT)); + caps.add(capabilityService.getCapability(RMPermissionModel.ADD_MODIFY_EVENT_DATES)); + + Role role = filePlanRoleService.createRole(filePlan, "Michelle Holt", "Michelle Holt", caps); + assertNotNull(role); + assertEquals("Michelle Holt", role.getName()); + assertEquals(2, role.getCapabilities().size()); + + assertTrue(filePlanRoleService.existsRole(filePlan, "Michelle Holt")); + + caps.add(capabilityService.getCapability(RMPermissionModel.AUTHORIZE_ALL_TRANSFERS)); + + role = filePlanRoleService.updateRole(filePlan, "Michelle Holt", "Michelle Wetherall", caps); + assertNotNull(role); + assertEquals("Michelle Holt", role.getName()); + assertEquals(3, role.getCapabilities().size()); + + assertTrue(filePlanRoleService.existsRole(filePlan, "Michelle Holt")); + + filePlanRoleService.deleteRole(filePlan, "Michelle Holt"); + + assertFalse(filePlanRoleService.existsRole(filePlan, "Michelle Holt")); + + return null; + } + }); + } + + public void testAssignRoleToAuthority() throws Exception + { + doTestInTransaction(new Test() + { + public Void run() + { + Set roles = filePlanRoleService.getRolesByUser(filePlan, rmUserName); + assertNotNull(roles); + assertEquals(1, roles.size()); + + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_NAME_RECORDS_MANAGER, rmUserName); + + roles = filePlanRoleService.getRolesByUser(filePlan, rmUserName); + assertNotNull(roles); + assertEquals(2, roles.size()); + + return null; + } + }); + } +} 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 0d54bb5445..37fc55d70d 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 @@ -661,6 +661,22 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase siteService.setMembership(COLLABORATION_SITE_ID, dmCollaborator, SiteModel.SITE_COLLABORATOR); } + /** + * Override to ensure the tests are run as the 'rmadmin' user by default. + */ + + @Override + protected A doTestInTransaction(Test test) + { + return super.doTestInTransaction(test, FilePlanRoleService.RM_ADMIN_USER); + } + + @Override + protected void doTestInTransaction(FailureTest test) + { + super.doTestInTransaction(test, FilePlanRoleService.RM_ADMIN_USER); + } + /** * Helper class to try and simplify {@link Void} tests. *