/* * (C) Copyright 2015-2017 Nuxeo (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * Vladimir Pasquier <vpasquier@nuxeo.com> */ package org.nuxeo.ecm.automation.core.operations.security; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.when; import static org.nuxeo.ecm.core.api.security.SecurityConstants.READ; import java.util.Calendar; import java.util.Collections; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.nuxeo.ecm.automation.AutomationService; import org.nuxeo.ecm.automation.OperationContext; import org.nuxeo.ecm.automation.OperationException; import org.nuxeo.ecm.automation.core.operations.document.AddPermission; import org.nuxeo.ecm.automation.core.operations.document.BlockPermissionInheritance; import org.nuxeo.ecm.automation.core.operations.document.UnblockPermissionInheritance; import org.nuxeo.ecm.automation.core.operations.document.ReplacePermission; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.impl.DocumentModelImpl; import org.nuxeo.ecm.core.api.security.ACL; import org.nuxeo.ecm.core.api.security.ACP; import org.nuxeo.ecm.core.api.security.Access; import org.nuxeo.ecm.core.api.security.AdministratorGroupsProvider; import org.nuxeo.ecm.core.test.CoreFeature; import org.nuxeo.ecm.platform.usermanager.UserManager; import org.nuxeo.runtime.api.Framework; import org.nuxeo.runtime.mockito.MockitoFeature; import org.nuxeo.runtime.mockito.RuntimeService; import org.nuxeo.runtime.services.config.ConfigurationService; import org.nuxeo.runtime.test.runner.Deploy; import org.nuxeo.runtime.test.runner.Features; import org.nuxeo.runtime.test.runner.FeaturesRunner; import org.nuxeo.runtime.test.runner.LocalDeploy; import com.google.inject.Inject; /** * @since 7.4 */ @RunWith(FeaturesRunner.class) @Features({ CoreFeature.class, MockitoFeature.class }) @Deploy("org.nuxeo.ecm.automation.core") @LocalDeploy("org.nuxeo.ecm.automation.core:test-operations.xml") public class PermissionAutomationTest { @Mock @RuntimeService protected AdministratorGroupsProvider administratorGroupsProvider; protected DocumentModel src; @Inject CoreSession session; @Inject AutomationService automationService; @Mock @RuntimeService private UserManager userManager; private final GregorianCalendar begin = new GregorianCalendar(2015, Calendar.JUNE, 20, 12, 34, 56); private final GregorianCalendar end = new GregorianCalendar(2015, Calendar.JULY, 14, 12, 34, 56); @Before public void initRepo() throws Exception { src = session.createDocumentModel("/", "src", "Folder"); src.setPropertyValue("dc:title", "Source"); src = session.createDocument(src); session.save(); src = session.getDocument(src.getRef()); when(userManager.getUserModel("existingUser")).thenReturn(new DocumentModelImpl("user")); when(userManager.getGroupModel("existingGroup")).thenReturn(new DocumentModelImpl("group")); when(administratorGroupsProvider.getAdministratorsGroups()).thenReturn( Collections.singletonList("administrators")); } @Test public void canAddPermissionForExistingUser() throws OperationException { canAddPermissionFor("existingUser"); } @Test public void canAddPermissionForExistingGroup() throws OperationException { canAddPermissionFor("existingGroup"); } @Test public void cannotAddPermissionForNonExistentUser() throws OperationException { cannotAddPermissionFor("nonExistentUser"); } @Test public void cannotAddPermissionForNonExistentGroup() throws OperationException { cannotAddPermissionFor("nonExistentGroup"); } @Test @LocalDeploy("org.nuxeo.ecm.automation.core:test-allow-virtual-user.xml") public void canAddPermissionForNonExistentUser() throws OperationException { ConfigurationService configService = Framework.getService(ConfigurationService.class); assertTrue(configService.isBooleanPropertyTrue(AddPermission.ALLOW_VIRTUAL_USER)); canAddPermissionFor("nonExistentUser"); } @Test @LocalDeploy("org.nuxeo.ecm.automation.core:test-allow-virtual-user.xml") public void canAddPermissionForNonExistentGroup() throws OperationException { ConfigurationService configService = Framework.getService(ConfigurationService.class); assertTrue(configService.isBooleanPropertyTrue(AddPermission.ALLOW_VIRTUAL_USER)); canAddPermissionFor("nonExistentGroup"); } private void canAddPermissionFor(String existingGroupOrUser) throws OperationException { try { OperationContext ctx = new OperationContext(session); ctx.setInput(src); Map<String, Object> params = new HashMap<>(); params.put("user", existingGroupOrUser); params.put("permission", "Write"); params.put("begin", begin); params.put("end", end); assertNull(src.getACP().getACL(ACL.LOCAL_ACL)); automationService.run(ctx, AddPermission.ID, params); assertNotNull(src.getACP().getACL(ACL.LOCAL_ACL)); assertEquals(end, src.getACP().getACL(ACL.LOCAL_ACL).get(0).getEnd()); } finally { // Tear down src.getACP().removeACEsByUsername(ACL.LOCAL_ACL, existingGroupOrUser); } } private void cannotAddPermissionFor(String nonExistentGroupOrUser) throws OperationException { OperationContext ctx = new OperationContext(session); ctx.setInput(src); Map<String, Object> params = new HashMap<>(); params.put("user", nonExistentGroupOrUser); params.put("permission", "Write"); params.put("begin", begin); params.put("end", end); assertNull(src.getACP().getACL(ACL.LOCAL_ACL)); try { automationService.run(ctx, AddPermission.ID, params); fail(); } catch (OperationException e) { String expectedMsg = "Failed to invoke operation Document.AddPermission with aliases [Document.AddACL]"; assertEquals(e.getMessage(), expectedMsg, e.getMessage()); } assertNull(src.getACP().getACL(ACL.LOCAL_ACL)); } @Test public void canReplacePermission() throws OperationException { try { OperationContext ctx = new OperationContext(session); ctx.setInput(src); // Add permission Map<String, Object> params = new HashMap<>(); params.put("user", "existingUser"); params.put("permission", "Write"); automationService.run(ctx, AddPermission.ID, params); ctx.setInput(src); // Replace permission params.put("user", "existingUser"); params.put("permission", "Everything"); params.put("id", "existingUser:Write:true:Administrator::"); assertEquals("Write", src.getACP().getACL(ACL.LOCAL_ACL).get(0).getPermission()); automationService.run(ctx, ReplacePermission.ID, params); src.refresh(); assertEquals("Everything", src.getACP().getACL(ACL.LOCAL_ACL).get(0).getPermission()); } finally { // Tear down src.getACP().removeACEsByUsername(ACL.LOCAL_ACL, "existingUser"); } } @Test public void canBlockPermissionInheritance() throws OperationException { ACP acp = src.getACP(); assertEquals(Access.GRANT, acp.getAccess("members", READ)); OperationContext ctx = new OperationContext(session); ctx.setInput(src); automationService.run(ctx, BlockPermissionInheritance.ID); src.refresh(); acp = src.getACP(); assertEquals(Access.DENY, acp.getAccess("members", READ)); } @Test public void canUnblockPermissionInheritance() throws OperationException { ACP acp = src.getACP(); acp.blockInheritance(ACL.LOCAL_ACL, session.getPrincipal().getName()); assertEquals(Access.DENY, acp.getAccess("members", READ)); OperationContext ctx = new OperationContext(session); ctx.setInput(src); automationService.run(ctx, UnblockPermissionInheritance.ID); src.refresh(); acp = src.getACP(); assertEquals(Access.GRANT, acp.getAccess("members", READ)); } }