From 64998b5c5345f3710bacc476fbff14327a3d4a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20=C5=BBurek?= Date: Fri, 8 Apr 2022 11:56:31 +0200 Subject: [PATCH] ACS-2744 Private action validation logic (#1051) --- .../repo/action/ActionExecutionContext.java | 93 +++++++++++ .../repo/action/ActionServiceImpl.java | 83 +++++++++- .../repo/action/RuntimeActionService.java | 12 +- .../alfresco/action-services-context.xml | 3 + .../java/org/alfresco/AllUnitTestsSuite.java | 1 + .../repo/action/ActionServiceImplTest.java | 124 ++++++++++++-- .../action/PrivateActionValidationTest.java | 152 ++++++++++++++++++ .../action/test-action-services-context.xml | 36 +++++ 8 files changed, 488 insertions(+), 16 deletions(-) create mode 100644 repository/src/main/java/org/alfresco/repo/action/ActionExecutionContext.java create mode 100644 repository/src/test/java/org/alfresco/repo/action/PrivateActionValidationTest.java diff --git a/repository/src/main/java/org/alfresco/repo/action/ActionExecutionContext.java b/repository/src/main/java/org/alfresco/repo/action/ActionExecutionContext.java new file mode 100644 index 0000000000..43f88b7037 --- /dev/null +++ b/repository/src/main/java/org/alfresco/repo/action/ActionExecutionContext.java @@ -0,0 +1,93 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2022 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.repo.action; + +import java.util.Objects; + +/** + * Instances of this class are responsible for holding an action id with additional data used to identify the action's + * execution context like: + * + */ +public class ActionExecutionContext +{ + private final String actionId; + private final String executionSource; + + private ActionExecutionContext(String actionId, String executionSource) + { + this.actionId = actionId; + this.executionSource = executionSource; + } + + String getActionId() + { + return actionId; + } + + String getExecutionSource() + { + return executionSource; + } + + boolean isExecutionSourceKnown() + { + return Objects.nonNull(executionSource); + } + + public static Builder builder(final String actionId) + { + Objects.requireNonNull(actionId); + return new Builder(actionId); + } + + public static class Builder + { + private final String actionId; + private String executionSource; + + private Builder(String actionId) + { + this.actionId = actionId; + } + + public ActionExecutionContext build() + { + return new ActionExecutionContext(actionId, executionSource); + } + + public Builder withExecutionSource(final String executionSource) + { + Objects.requireNonNull(executionSource); + this.executionSource = executionSource; + return this; + } + } +} diff --git a/repository/src/main/java/org/alfresco/repo/action/ActionServiceImpl.java b/repository/src/main/java/org/alfresco/repo/action/ActionServiceImpl.java index 23d0bfdcf2..ec9de682f9 100644 --- a/repository/src/main/java/org/alfresco/repo/action/ActionServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/action/ActionServiceImpl.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2020 Alfresco Software Limited + * Copyright (C) 2005 - 2022 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -33,7 +33,14 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Properties; import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.alfresco.model.ContentModel; import org.alfresco.repo.action.evaluator.ActionConditionEvaluator; @@ -120,6 +127,8 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A private ActionTrackingService actionTrackingService; private PolicyComponent policyComponent; private ActionServiceMonitor monitor; + private Properties configProperties; + private ActionExecutionValidator actionExecutionValidator; /** * The asynchronous action execution queues map of name, queue @@ -236,7 +245,17 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A { this.asynchronousActionExecutionQueues = asynchronousActionExecutionQueues; } - + + public void setConfigurationProperties(Properties properties) + { + this.configProperties = properties; + } + + protected Properties getConfigurationProperties() + { + return configProperties; + } + /** * This method registers an {@link AsynchronousActionExecutionQueue} with the {@link ActionService}. * @param key String @@ -256,6 +275,11 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A ActionModel.TYPE_ACTION_PARAMETER, new JavaBehaviour(this, "getCopyCallback")); this.policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyComplete"), ActionModel.TYPE_ACTION_PARAMETER, new JavaBehaviour(this, "onCopyComplete")); + if (configProperties == null) + { + configProperties = applicationContext.getBean("global-properties", Properties.class); + } + actionExecutionValidator = new ActionExecutionValidator(configProperties::getProperty, actionDefinitions::containsKey); } /** @@ -1870,5 +1894,58 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A LoggingAwareExecuter executer = (LoggingAwareExecuter) this.applicationContext.getBean(action.getActionDefinitionName()); return executer.onLogException(logger,t, message); } - + + @Override + public boolean isExposed(ActionExecutionContext actionExecutionContext) + { + return actionExecutionValidator.isExposed(actionExecutionContext); + } + + static class ActionExecutionValidator + { + private final Function config; + private final Predicate isPublic; + + ActionExecutionValidator(Function config, Predicate isPublic) + { + this.config = Objects.requireNonNull(config); + this.isPublic = Objects.requireNonNull(isPublic); + } + + boolean isExposed(ActionExecutionContext actionExecutionContext) + { + Objects.requireNonNull(actionExecutionContext); + return isExposedInConfig(actionExecutionContext).orElseGet(() -> isPublic(actionExecutionContext)); + } + + private Optional isExposedInConfig(ActionExecutionContext actionExecutionContext) + { + return getConfigKeys(actionExecutionContext). + map(config). + filter(Objects::nonNull). + map(Boolean::parseBoolean). + findFirst(); + } + + private Boolean isPublic(ActionExecutionContext actionExecutionContext) + { + return isPublic.test(actionExecutionContext.getActionId()); + } + + private static Stream getConfigKeys(ActionExecutionContext actionExecutionContext) + { + if (actionExecutionContext.isExecutionSourceKnown()) + { + return Stream.of( + getConfigKey(actionExecutionContext.getExecutionSource(), actionExecutionContext.getActionId()), + getConfigKey(actionExecutionContext.getActionId())); + } + return Stream.of(getConfigKey(actionExecutionContext.getActionId())); + } + + static String getConfigKey(String... parts) + { + return Stream.of(parts).collect(Collectors.joining(".", "org.alfresco.repo.action.", ".exposed")); + } + } } diff --git a/repository/src/main/java/org/alfresco/repo/action/RuntimeActionService.java b/repository/src/main/java/org/alfresco/repo/action/RuntimeActionService.java index d4c5f30de7..0b1b50035a 100644 --- a/repository/src/main/java/org/alfresco/repo/action/RuntimeActionService.java +++ b/repository/src/main/java/org/alfresco/repo/action/RuntimeActionService.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited + * Copyright (C) 2005 - 2022 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -125,4 +125,14 @@ public interface RuntimeActionService * @return true if it was handled, false for default handling */ public boolean onLogException(Action action, Log logger, Throwable t, String message); + + /** + * Allows you to check if an action can be executed/used in a given execution context + * @param actionExecutionContext describes action and its execution context + * @return true if action can be executed, false otherwise + */ + default boolean isExposed(ActionExecutionContext actionExecutionContext) + { + return true; + } } diff --git a/repository/src/main/resources/alfresco/action-services-context.xml b/repository/src/main/resources/alfresco/action-services-context.xml index 8c7f5258b4..3e55065a58 100644 --- a/repository/src/main/resources/alfresco/action-services-context.xml +++ b/repository/src/main/resources/alfresco/action-services-context.xml @@ -75,6 +75,9 @@ + + + diff --git a/repository/src/test/java/org/alfresco/AllUnitTestsSuite.java b/repository/src/test/java/org/alfresco/AllUnitTestsSuite.java index a956aeb879..d5006e9bd1 100644 --- a/repository/src/test/java/org/alfresco/AllUnitTestsSuite.java +++ b/repository/src/test/java/org/alfresco/AllUnitTestsSuite.java @@ -176,6 +176,7 @@ import org.junit.runners.Suite; org.alfresco.repo.action.CompositeActionImplTest.class, org.alfresco.repo.action.CompositeActionConditionImplTest.class, org.alfresco.repo.action.executer.TransformActionExecuterTest.class, + org.alfresco.repo.action.PrivateActionValidationTest.class, org.alfresco.repo.audit.AuditableAnnotationTest.class, org.alfresco.repo.audit.PropertyAuditFilterTest.class, org.alfresco.repo.audit.access.NodeChangeTest.class, diff --git a/repository/src/test/java/org/alfresco/repo/action/ActionServiceImplTest.java b/repository/src/test/java/org/alfresco/repo/action/ActionServiceImplTest.java index f227199b14..33d2df06e2 100644 --- a/repository/src/test/java/org/alfresco/repo/action/ActionServiceImplTest.java +++ b/repository/src/test/java/org/alfresco/repo/action/ActionServiceImplTest.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited + * Copyright (C) 2005 - 2022 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -25,28 +25,27 @@ */ package org.alfresco.repo.action; +import static org.alfresco.repo.action.ActionExecutionContext.builder; + import java.io.Serializable; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Properties; import org.alfresco.model.ContentModel; import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator; import org.alfresco.repo.action.evaluator.InCategoryEvaluator; import org.alfresco.repo.action.evaluator.NoConditionEvaluator; import org.alfresco.repo.action.evaluator.compare.ComparePropertyValueOperation; -import org.alfresco.repo.action.executer.ActionExecuter; import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; import org.alfresco.repo.action.executer.AddFeaturesActionExecuter; import org.alfresco.repo.action.executer.CheckInActionExecuter; import org.alfresco.repo.action.executer.CheckOutActionExecuter; import org.alfresco.repo.action.executer.CompositeActionExecuter; import org.alfresco.repo.action.executer.MoveActionExecuter; -import org.alfresco.repo.action.executer.ScriptActionExecuter; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper; @@ -65,19 +64,14 @@ import org.alfresco.service.cmr.action.CompositeActionCondition; import org.alfresco.service.cmr.action.ParameterDefinition; import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.repository.ContentData; -import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.alfresco.test_category.BaseSpringTestsCategory; -import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.BaseAlfrescoSpringTest; import org.alfresco.util.GUID; -import org.alfresco.util.PropertyMap; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -103,13 +97,18 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest private NodeRef nodeRef; private NodeRef folder; private RetryingTransactionHelper transactionHelper; + private Properties globalConfig; + private RuntimeActionService runtimeActionService; + @Before public void before() throws Exception { super.before(); - this.transactionHelper = (RetryingTransactionHelper)this.applicationContext.getBean("retryingTransactionHelper"); + this.transactionHelper = applicationContext.getBean("retryingTransactionHelper", RetryingTransactionHelper.class); + this.globalConfig = applicationContext.getBean("global-properties", Properties.class); + this.runtimeActionService = this.applicationContext.getBean("actionService", RuntimeActionService.class); // Create the node used for tests this.nodeRef = this.nodeService.createNode( @@ -1295,6 +1294,89 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest assertEquals(123455, action.getExecutionEndDate().getTime()); assertEquals(null, action.getExecutionFailureMessage()); } + + @Test + public void testActionExposureBasedOnConfiguration() + { + globalConfig.remove("org.alfresco.repo.action.public-test-action.exposed"); + globalConfig.remove("org.alfresco.repo.action.source.public-test-action.exposed"); + globalConfig.remove("org.alfresco.repo.action.unknown.public-test-action.exposed"); + assertTrue(runtimeActionService.isExposed(builder("public-test-action").build())); + assertTrue(runtimeActionService.isExposed(builder("public-test-action").withExecutionSource("source").build())); + assertTrue(runtimeActionService.isExposed(builder("public-test-action").withExecutionSource("unknown").build())); + + globalConfig.setProperty("org.alfresco.repo.action.public-test-action.exposed", "true"); + globalConfig.remove("org.alfresco.repo.action.source.public-test-action.exposed"); + globalConfig.remove("org.alfresco.repo.action.unknown.public-test-action.exposed"); + assertTrue(runtimeActionService.isExposed(builder("public-test-action").build())); + assertTrue(runtimeActionService.isExposed(builder("public-test-action").withExecutionSource("source").build())); + assertTrue(runtimeActionService.isExposed(builder("public-test-action").withExecutionSource("unknown").build())); + + globalConfig.setProperty("org.alfresco.repo.action.public-test-action.exposed", "false"); + globalConfig.remove("org.alfresco.repo.action.source.public-test-action.exposed"); + globalConfig.remove("org.alfresco.repo.action.unknown.public-test-action.exposed"); + assertFalse(runtimeActionService.isExposed(builder("public-test-action").build())); + assertFalse(runtimeActionService.isExposed(builder("public-test-action").withExecutionSource("source").build())); + assertFalse(runtimeActionService.isExposed(builder("public-test-action").withExecutionSource("unknown").build())); + + globalConfig.remove("org.alfresco.repo.action.public-test-action.exposed"); + globalConfig.setProperty("org.alfresco.repo.action.source.public-test-action.exposed", "true"); + globalConfig.remove("org.alfresco.repo.action.unknown.public-test-action.exposed"); + assertTrue(runtimeActionService.isExposed(builder("public-test-action").build())); + assertTrue(runtimeActionService.isExposed(builder("public-test-action").withExecutionSource("source").build())); + assertTrue(runtimeActionService.isExposed(builder("public-test-action").withExecutionSource("unknown").build())); + + globalConfig.remove("org.alfresco.repo.action.public-test-action.exposed"); + globalConfig.setProperty("org.alfresco.repo.action.source.public-test-action.exposed", "false"); + globalConfig.remove("org.alfresco.repo.action.unknown.public-test-action.exposed"); + assertTrue(runtimeActionService.isExposed(builder("public-test-action").build())); + assertFalse(runtimeActionService.isExposed(builder("public-test-action").withExecutionSource("source").build())); + assertTrue(runtimeActionService.isExposed(builder("public-test-action").withExecutionSource("unknown").build())); + + globalConfig.remove("org.alfresco.repo.action.private-test-action.exposed"); + globalConfig.remove("org.alfresco.repo.action.source.private-test-action.exposed"); + globalConfig.remove("org.alfresco.repo.action.unknown.private-test-action.exposed"); + assertFalse(runtimeActionService.isExposed(builder("private-test-action").build())); + assertFalse(runtimeActionService.isExposed(builder("private-test-action").withExecutionSource("source").build())); + assertFalse(runtimeActionService.isExposed(builder("private-test-action").withExecutionSource("unknown").build())); + + globalConfig.setProperty("org.alfresco.repo.action.private-test-action.exposed", "true"); + globalConfig.remove("org.alfresco.repo.action.source.private-test-action.exposed"); + globalConfig.remove("org.alfresco.repo.action.unknown.private-test-action.exposed"); + assertTrue(runtimeActionService.isExposed(builder("private-test-action").build())); + assertTrue(runtimeActionService.isExposed(builder("private-test-action").withExecutionSource("source").build())); + assertTrue(runtimeActionService.isExposed(builder("private-test-action").withExecutionSource("unknown").build())); + + globalConfig.setProperty("org.alfresco.repo.action.private-test-action.exposed", "false"); + globalConfig.remove("org.alfresco.repo.action.source.private-test-action.exposed"); + globalConfig.remove("org.alfresco.repo.action.unknown.private-test-action.exposed"); + assertFalse(runtimeActionService.isExposed(builder("private-test-action").build())); + assertFalse(runtimeActionService.isExposed(builder("private-test-action").withExecutionSource("source").build())); + assertFalse(runtimeActionService.isExposed(builder("private-test-action").withExecutionSource("unknown").build())); + + globalConfig.remove("org.alfresco.repo.action.private-test-action.exposed"); + globalConfig.setProperty("org.alfresco.repo.action.source.private-test-action.exposed", "true"); + globalConfig.remove("org.alfresco.repo.action.unknown.private-test-action.exposed"); + assertFalse(runtimeActionService.isExposed(builder("private-test-action").build())); + assertTrue(runtimeActionService.isExposed(builder("private-test-action").withExecutionSource("source").build())); + assertFalse(runtimeActionService.isExposed(builder("private-test-action").withExecutionSource("unknown").build())); + + globalConfig.remove("org.alfresco.repo.action.private-test-action.exposed"); + globalConfig.setProperty("org.alfresco.repo.action.source.private-test-action.exposed", "false"); + globalConfig.remove("org.alfresco.repo.action.unknown.private-test-action.exposed"); + assertFalse(runtimeActionService.isExposed(builder("private-test-action").build())); + assertFalse(runtimeActionService.isExposed(builder("private-test-action").withExecutionSource("source").build())); + assertFalse(runtimeActionService.isExposed(builder("private-test-action").withExecutionSource("unknown").build())); + } + + @Test + public void testIfGlobalConfigurationIsUsedEvenIfNotInjectedBySpring() + { + TestExtendedActionServiceImpl extended = applicationContext.getBean("extendedActionServiceWithoutConfigurationProperty", TestExtendedActionServiceImpl.class); + + assertNotNull(extended.getConfigurationProperties()); + assertSame(globalConfig, extended.getConfigurationProperties()); + } /** * This method returns an {@link Action} which will fail when executed. @@ -1509,8 +1591,26 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest throw new ActionServiceTransientException("action failed intentionally in " + TransientFailActionExecuter.class.getSimpleName()); } } - + public static class NoOpActionExecuter extends ActionExecuterAbstractBase + { + @Override + protected void addParameterDefinitions(List paramList) + { + //do nothing + } + + @Override + protected void executeImpl(Action action, NodeRef actionedUponNodeRef) + { + //do nothing + } + } + + public static class TestExtendedActionServiceImpl extends ActionServiceImpl + { + + } protected static class CancellableSleepAction extends ActionImpl implements CancellableAction { diff --git a/repository/src/test/java/org/alfresco/repo/action/PrivateActionValidationTest.java b/repository/src/test/java/org/alfresco/repo/action/PrivateActionValidationTest.java new file mode 100644 index 0000000000..3f4f98b7c6 --- /dev/null +++ b/repository/src/test/java/org/alfresco/repo/action/PrivateActionValidationTest.java @@ -0,0 +1,152 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2022 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.repo.action; + +import static org.alfresco.repo.action.ActionExecutionContext.builder; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.action.ActionServiceImpl.ActionExecutionValidator; +import org.junit.Assert; +import org.junit.Test; + +public class PrivateActionValidationTest +{ + @Test + public void shouldFailOnNullContext() + { + final ActionExecutionValidator validator = givenActionExecutionValidator(Map.of(), Set.of()); + + try + { + validator.isExposed(null); + } + catch (NullPointerException e) + { + assertNotNull(e); + return; + } + fail("Expected NPE."); + } + + @Test + public void privateActionShouldNotBeExposedByDefault() + { + final ActionExecutionValidator validator = givenActionExecutionValidator(Map.of(), Set.of()); + + Assert.assertFalse(validator.isExposed(builder("privateA").build())); + Assert.assertFalse(validator.isExposed(builder("privateA").withExecutionSource("test").build())); + } + + @Test + public void publicActionShouldBeExposedByDefault() + { + final ActionExecutionValidator validator = givenActionExecutionValidator(Map.of(), Set.of("publicA")); + + Assert.assertTrue(validator.isExposed(builder("publicA").build())); + Assert.assertTrue(validator.isExposed(builder("publicA").withExecutionSource("test").build())); + } + + @Test + public void privateActionShouldBeExposedByConfigurationBasedOnActionId() + { + final ActionExecutionValidator validator = givenActionExecutionValidator(Map.of( + "org.alfresco.repo.action.privateA.exposed", "true"), Set.of()); + + Assert.assertTrue(validator.isExposed(builder("privateA").build())); + Assert.assertTrue(validator.isExposed(builder("privateA").withExecutionSource("test").build())); + Assert.assertTrue(validator.isExposed(builder("privateA").withExecutionSource("test2").build())); + + Assert.assertFalse(validator.isExposed(builder("privateB").build())); + Assert.assertFalse(validator.isExposed(builder("privateB").withExecutionSource("test").build())); + Assert.assertFalse(validator.isExposed(builder("privateB").withExecutionSource("test2").build())); + } + + @Test + public void privateActionShouldBeExposedByConfigurationBasedOnActionIdAndExecutionSource() + { + final ActionExecutionValidator validator = givenActionExecutionValidator(Map.of( + "org.alfresco.repo.action.test.privateA.exposed", "true"), Set.of()); + + Assert.assertFalse(validator.isExposed(builder("privateA").build())); + Assert.assertTrue(validator.isExposed(builder("privateA").withExecutionSource("test").build())); + Assert.assertFalse(validator.isExposed(builder("privateA").withExecutionSource("test2").build())); + + Assert.assertFalse(validator.isExposed(builder("privateB").build())); + Assert.assertFalse(validator.isExposed(builder("privateB").withExecutionSource("test").build())); + Assert.assertFalse(validator.isExposed(builder("privateB").withExecutionSource("test2").build())); + } + + @Test + public void executionSourceConfigurationShouldTakePrecedenceOverGeneralConfigurationForPrivateAction() + { + final ActionExecutionValidator validator = givenActionExecutionValidator(Map.of( + "org.alfresco.repo.action.test.privateA.exposed", "true", + "org.alfresco.repo.action.privateA.exposed", "false"), Set.of()); + + Assert.assertFalse(validator.isExposed(builder("privateA").build())); + Assert.assertTrue(validator.isExposed(builder("privateA").withExecutionSource("test").build())); + } + + @Test + public void publicActionShouldNotBeExposedByConfigurationBasedOnActionId() + { + final ActionExecutionValidator validator = givenActionExecutionValidator(Map.of( + "org.alfresco.repo.action.publicA.exposed", "false"), Set.of("publicA")); + + Assert.assertFalse(validator.isExposed(builder("publicA").build())); + Assert.assertFalse(validator.isExposed(builder("publicA").withExecutionSource("test").build())); + } + + @Test + public void publicActionShouldNotBeExposedByConfigurationBasedOnActionIdAndExecutionSource() + { + final ActionExecutionValidator validator = givenActionExecutionValidator(Map.of( + "org.alfresco.repo.action.test.publicA.exposed", "false"), Set.of("publicA")); + + Assert.assertTrue(validator.isExposed(builder("publicA").build())); + Assert.assertFalse(validator.isExposed(builder("publicA").withExecutionSource("test").build())); + } + + @Test + public void executionSourceConfigurationShouldTakePrecedenceOverGeneralConfigurationForPublicAction() + { + final ActionExecutionValidator validator = givenActionExecutionValidator(Map.of( + "org.alfresco.repo.action.test.publicA.exposed", "false", + "org.alfresco.repo.action.publicA.exposed", "true"), Set.of("publicA")); + + Assert.assertTrue(validator.isExposed(builder("publicA").build())); + Assert.assertFalse(validator.isExposed(builder("publicA").withExecutionSource("test").build())); + } + + private ActionExecutionValidator givenActionExecutionValidator(Map configuration, Set publicActions) + { + return new ActionExecutionValidator(configuration::get, publicActions::contains); + } +} diff --git a/repository/src/test/resources/org/alfresco/repo/action/test-action-services-context.xml b/repository/src/test/resources/org/alfresco/repo/action/test-action-services-context.xml index 93586a134b..6ba0bbf43d 100644 --- a/repository/src/test/resources/org/alfresco/repo/action/test-action-services-context.xml +++ b/repository/src/test/resources/org/alfresco/repo/action/test-action-services-context.xml @@ -11,6 +11,18 @@ 1000 + + + + true + + + + + + false + + @@ -31,4 +43,28 @@ + + + + + + + + + + + + + + + + + + + + + + + +