Feature/acs 3169 implement security mechanism for mail action (#1189)

Implementing access restriction for actions
Updating copyrights of modified files
Moving core restriction processing to an AbstractBase class
PR Review fixes
Slight improvement for future extensibility
This commit is contained in:
Marcin Strankowski
2022-07-06 16:07:40 +02:00
committed by GitHub
parent 92d010842a
commit 43480468af
21 changed files with 646 additions and 220 deletions

View File

@@ -168,6 +168,7 @@
<property name="nodeService" ref="NodeService"/> <property name="nodeService" ref="NodeService"/>
<property name="ruleService" ref="RuleService"/> <property name="ruleService" ref="RuleService"/>
<property name="actionService" ref="ActionService"/> <property name="actionService" ref="ActionService"/>
<property name="runtimeActionService" ref="actionService"/>
<property name="dictionaryService" ref="DictionaryService"/> <property name="dictionaryService" ref="DictionaryService"/>
<property name="fileFolderService" ref="FileFolderService"/> <property name="fileFolderService" ref="FileFolderService"/>
<property name="namespaceService" ref="NamespaceService" /> <property name="namespaceService" ref="NamespaceService" />

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2022 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -27,6 +27,7 @@ package org.alfresco.repo.web.scripts.action;
import java.util.Map; import java.util.Map;
import org.alfresco.repo.action.access.ActionAccessRestriction;
import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ExecutionSummary; import org.alfresco.service.cmr.action.ExecutionSummary;
import org.springframework.extensions.webscripts.Cache; import org.springframework.extensions.webscripts.Cache;
@@ -58,6 +59,7 @@ public abstract class AbstractExecuteActionWebscript extends AbstractActionWebsc
// Ask for it to be run in the background // Ask for it to be run in the background
// It will be available to execute once the webscript finishes // It will be available to execute once the webscript finishes
ActionAccessRestriction.setActionContext(action, ActionAccessRestriction.V0_ACTION_CONTEXT);
actionService.executeAction( actionService.executeAction(
action, null, action, null,
false, true false, true

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2022 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -38,6 +38,8 @@ import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.action.ActionConditionImpl; import org.alfresco.repo.action.ActionConditionImpl;
import org.alfresco.repo.action.ActionImpl; import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.CompositeActionImpl; import org.alfresco.repo.action.CompositeActionImpl;
import org.alfresco.repo.action.RuntimeActionService;
import org.alfresco.repo.action.access.ActionAccessRestriction;
import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionCondition; import org.alfresco.service.cmr.action.ActionCondition;
import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.action.ActionService;
@@ -85,6 +87,8 @@ public abstract class AbstractRuleWebScript extends DeclarativeWebScript
protected FileFolderService fileFolderService; protected FileFolderService fileFolderService;
protected NamespaceService namespaceService; protected NamespaceService namespaceService;
private RuntimeActionService runtimeActionService;
/** /**
* Sets the node service instance * Sets the node service instance
* *
@@ -145,6 +149,10 @@ public abstract class AbstractRuleWebScript extends DeclarativeWebScript
this.namespaceService = namespaceService; this.namespaceService = namespaceService;
} }
public void setRuntimeActionService(RuntimeActionService runtimeActionService) {
this.runtimeActionService = runtimeActionService;
}
/** /**
* Parses the request and providing it's valid returns the NodeRef. * Parses the request and providing it's valid returns the NodeRef.
* *
@@ -432,10 +440,22 @@ public abstract class AbstractRuleWebScript extends DeclarativeWebScript
protected void checkRule(Rule rule) protected void checkRule(Rule rule)
{ {
List<String> ruleTypes = rule.getRuleTypes(); List<Action> actions = ((CompositeActionImpl) rule.getAction()).getActions();
if (ruleTypes.contains(RULE_OUTBOUND))
checkRestrictedAccessActions(actions);
checkRuleOutboundHasNoCheckOutAction(rule, actions);
}
private void checkRestrictedAccessActions(List<Action> actions) {
for (Action action : actions) {
ActionAccessRestriction.setActionContext(action, ActionAccessRestriction.RULE_ACTION_CONTEXT);
runtimeActionService.verifyActionAccessRestrictions(action);
}
}
private void checkRuleOutboundHasNoCheckOutAction(Rule rule, List<Action> actions) {
if (rule.getRuleTypes().contains(RULE_OUTBOUND))
{ {
List<Action> actions = ((CompositeActionImpl) rule.getAction()).getActions();
for (Action action : actions) for (Action action : actions)
{ {
if (action.getActionDefinitionName().equalsIgnoreCase(ACTION_CHECK_OUT)) if (action.getActionDefinitionName().equalsIgnoreCase(ACTION_CHECK_OUT))

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2022 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -30,6 +30,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.alfresco.repo.action.ActionImpl; import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.access.ActionAccessRestriction;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -89,6 +90,7 @@ public class ActionQueuePost extends AbstractRuleWebScript
} }
// Execute action // Execute action
ActionAccessRestriction.setActionContext(action, ActionAccessRestriction.V0_ACTION_CONTEXT);
actionService.executeAction(action, actionedUponNode, true, async); actionService.executeAction(action, actionedUponNode, true, async);
// Prepair model // Prepair model

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited * Copyright (C) 2005 - 2022 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -26,6 +26,7 @@
package org.alfresco.rest.api.impl; package org.alfresco.rest.api.impl;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.action.access.ActionAccessRestriction;
import org.alfresco.rest.api.Actions; import org.alfresco.rest.api.Actions;
import org.alfresco.rest.api.model.Action; import org.alfresco.rest.api.model.Action;
import org.alfresco.rest.api.model.ActionDefinition; import org.alfresco.rest.api.model.ActionDefinition;
@@ -286,6 +287,7 @@ public class ActionsImpl implements Actions
cmrAction = actionService.createAction(action.getActionDefinitionId()); cmrAction = actionService.createAction(action.getActionDefinitionId());
} }
ActionAccessRestriction.setActionContext(cmrAction, ActionAccessRestriction.V1_ACTION_CONTEXT);
actionService.executeAction(cmrAction, actionedUponNodeRef, true, true); actionService.executeAction(cmrAction, actionedUponNodeRef, true, true);
// Create user result. // Create user result.

View File

@@ -696,6 +696,7 @@
<property name="nodeService" ref="NodeService"/> <property name="nodeService" ref="NodeService"/>
<property name="ruleService" ref="RuleService"/> <property name="ruleService" ref="RuleService"/>
<property name="actionService" ref="ActionService"/> <property name="actionService" ref="ActionService"/>
<property name="runtimeActionService" ref="actionService"/>
<property name="dictionaryService" ref="DictionaryService"/> <property name="dictionaryService" ref="DictionaryService"/>
<property name="fileFolderService" ref="FileFolderService"/> <property name="fileFolderService" ref="FileFolderService"/>
<property name="namespaceService" ref="NamespaceService" /> <property name="namespaceService" ref="NamespaceService" />

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2020 Alfresco Software Limited * Copyright (C) 2005 - 2022 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -36,6 +36,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.access.ActionAccessRestriction;
import org.alfresco.repo.action.evaluator.ActionConditionEvaluator; import org.alfresco.repo.action.evaluator.ActionConditionEvaluator;
import org.alfresco.repo.action.executer.ActionExecuter; import org.alfresco.repo.action.executer.ActionExecuter;
import org.alfresco.repo.action.executer.CompositeActionExecuter; import org.alfresco.repo.action.executer.CompositeActionExecuter;
@@ -141,6 +142,11 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A
*/ */
private Map<String, ActionDefinition> actionDefinitions = new HashMap<String, ActionDefinition>(); private Map<String, ActionDefinition> actionDefinitions = new HashMap<String, ActionDefinition>();
/**
* Action access restricted executers
*/
private Map<String, ActionExecuter> actionExecuters = new HashMap<>();
/** /**
* All the parameter constraints * All the parameter constraints
*/ */
@@ -298,7 +304,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A
*/ */
public List<ActionDefinition> getActionDefinitions() public List<ActionDefinition> getActionDefinitions()
{ {
return new ArrayList<ActionDefinition>(this.actionDefinitions.values()); return new ArrayList<>(this.actionDefinitions.values());
} }
/** /**
@@ -588,11 +594,29 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A
} }
else else
{ {
verifyActionAccessRestrictions(action);
// Add to the post transaction pending action list // Add to the post transaction pending action list
addPostTransactionPendingAction(action, actionedUponNodeRef, checkConditions, actionChain); addPostTransactionPendingAction(action, actionedUponNodeRef, checkConditions, actionChain);
} }
} }
/**
* @see RuntimeActionService#verifyActionAccessRestrictions(Action action)
*/
@Override
public void verifyActionAccessRestrictions(Action action) {
getActionExecuter(action.getActionDefinitionName())
.verifyActionAccessRestrictions(action);
}
private ActionExecuter getActionExecuter(String actionDefName) {
if (!actionExecuters.containsKey(actionDefName)) {
actionExecuters.put(actionDefName, applicationContext.getBean(actionDefName, ActionExecuter.class));
}
return actionExecuters.get(actionDefName);
}
private boolean isExecuteAsynchronously(Action action, NodeRef actionedUponNodeRef, boolean executeAsynchronously) private boolean isExecuteAsynchronously(Action action, NodeRef actionedUponNodeRef, boolean executeAsynchronously)
{ {
if (executeAsynchronously == false) if (executeAsynchronously == false)

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2022 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -96,6 +96,13 @@ public interface RuntimeActionService
*/ */
void saveActionImpl(NodeRef actionNodeRef, Action action); void saveActionImpl(NodeRef actionNodeRef, Action action);
/**
* Verify users access to an action with restrictions
*
* @param action
*/
void verifyActionAccessRestrictions(Action action);
/** /**
* Perform low-level action execution * Perform low-level action execution
*/ */

View File

@@ -0,0 +1,34 @@
/*
* #%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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.action.access;
public class ActionAccessException extends RuntimeException {
public ActionAccessException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,53 @@
/*
* #%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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.action.access;
import org.alfresco.service.cmr.action.Action;
public interface ActionAccessRestriction {
String ACTION_CONTEXT_PARAM_NAME = "actionContext";
String RULE_ACTION_CONTEXT = "rule";
String FORM_PROCESSOR_ACTION_CONTEXT = "formProcessor";
String V0_ACTION_CONTEXT = "v0";
String V1_ACTION_CONTEXT = "v1";
static void setActionContext(Action action, String actionContext) {
action.setParameterValue(ACTION_CONTEXT_PARAM_NAME, actionContext);
}
static String getActionContext(Action action) {
return (String) action.getParameterValue(ACTION_CONTEXT_PARAM_NAME);
}
/**
* Verify action access restriction
*
* @param action
*/
void verifyAccessRestriction(Action action);
}

View File

@@ -0,0 +1,157 @@
/*
* #%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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.action.access;
import org.alfresco.repo.action.ActionModel;
import org.alfresco.repo.rule.RuleModel;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public abstract class ActionAccessRestrictionAbstractBase implements ActionAccessRestriction {
private static final Set<String> CONTROLLED_ACTION_ACCESS_CONTEXT =
Set.of(ActionAccessRestriction.RULE_ACTION_CONTEXT, ActionAccessRestriction.FORM_PROCESSOR_ACTION_CONTEXT,
ActionAccessRestriction.V0_ACTION_CONTEXT, ActionAccessRestriction.V1_ACTION_CONTEXT);
protected NodeService nodeService;
private Properties configProperties;
public void setNodeService(NodeService nodeService) {
this.nodeService = nodeService;
}
public void setConfigProperties(Properties configProperties) {
this.configProperties = configProperties;
}
/**
* Base for verifying access restriction,
* manages common checks for exposing action in config or action being ran as a consequence of running a rule (safe)
*
* @param action
*/
public void verifyAccessRestriction(Action action) {
if (blockAccessRestriction(action)) {
return;
}
innerVerifyAccessRestriction(action);
}
protected boolean blockAccessRestriction(Action action) {
return isActionExposed(action) || isActionCausedByRule(action);
}
protected boolean isActionExposed(Action action) {
return !isActionFromControlledContext(action) || isExposedInConfig(action).orElse(Boolean.FALSE);
}
private boolean isActionFromControlledContext(Action action) {
String actionContext = ActionAccessRestriction.getActionContext(action);
return actionContext != null && CONTROLLED_ACTION_ACCESS_CONTEXT.contains(actionContext);
}
private Optional<Boolean> isExposedInConfig(Action action)
{
return getConfigKeys(action).
map(configProperties::getProperty).
filter(Objects::nonNull).
map(Boolean::parseBoolean).
findFirst();
}
private Stream<String> getConfigKeys(Action action)
{
String context = ActionAccessRestriction.getActionContext(action);
String actionName = action.getActionDefinitionName();
if (context != null)
{
return Stream.of(
getConfigKey(context, actionName),
getConfigKey(context));
}
return Stream.of(getConfigKey(actionName));
}
private String getConfigKey(String... parts)
{
return Stream.of(parts)
.collect(Collectors.joining(".", "org.alfresco.repo.action.", ".exposed"));
}
/**
* Checks the hierarchy of primary parents of action node ref to look for Rule node ref
* Finding it means that the action was triggered by an existing rule, which are deemed secure
* as their validation happens at their setup.
*
* @param action
* @return
*/
protected boolean isActionCausedByRule(Action action) {
if (action.getNodeRef() == null) {
return false;
}
NodeRef ruleParent = getPotentialRuleParent(action.getNodeRef());
return isRule(ruleParent);
}
private NodeRef getPotentialRuleParent(NodeRef nodeRef) {
NodeRef parentNode = nodeService.getPrimaryParent(nodeRef).getParentRef();
while (isCompositeAction(parentNode))
{
parentNode = nodeService.getPrimaryParent(parentNode).getParentRef();
}
return parentNode;
}
private boolean isCompositeAction(NodeRef nodeRef) {
return ActionModel.TYPE_COMPOSITE_ACTION.equals(nodeService.getType(nodeRef));
}
private boolean isRule(NodeRef nodeRef) {
return RuleModel.TYPE_RULE.equals(nodeService.getType(nodeRef));
}
/**
* Restriction specific implementation of extensions
* @param action
*/
protected abstract void innerVerifyAccessRestriction(Action action);
}

View File

@@ -0,0 +1,53 @@
/*
* #%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 <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.action.access;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.security.AuthorityService;
public class AdminActionAccessRestriction extends ActionAccessRestrictionAbstractBase {
private AuthorityService authorityService;
public void setAuthorityService(AuthorityService authorityService) {
this.authorityService = authorityService;
}
/**
* Only admin can run action access restriction
*
* @param action
*/
protected void innerVerifyAccessRestriction(Action action) {
boolean isAdminOrSystemUser = authorityService.hasAdminAuthority() || AuthenticationUtil.isRunAsUserTheSystemUser();
if (!isAdminOrSystemUser) {
throw new ActionAccessException("Only admin or system user is allowed to define uses of " +
"or directly execute this action");
}
}
}

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2020 Alfresco Software Limited * Copyright (C) 2005 - 2022 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -77,6 +77,15 @@ public interface ActionExecuter
*/ */
ActionDefinition getActionDefinition(); ActionDefinition getActionDefinition();
/**
* Verify action access restrictions
*
* @param action
*/
default void verifyActionAccessRestrictions(Action action){
//Will be extended by ActionExecutor implementation, to provide security if needed
};
/** /**
* Execute the action executer * Execute the action executer
* *

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2022 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -25,12 +25,15 @@
*/ */
package org.alfresco.repo.action.executer; package org.alfresco.repo.action.executer;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import org.alfresco.api.AlfrescoPublicApi; import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.repo.action.ActionDefinitionImpl; import org.alfresco.repo.action.ActionDefinitionImpl;
import org.alfresco.repo.action.ParameterizedItemAbstractBase; import org.alfresco.repo.action.ParameterizedItemAbstractBase;
import org.alfresco.repo.action.access.ActionAccessRestriction;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.Action;
@@ -65,6 +68,9 @@ public abstract class ActionExecuterAbstractBase extends ParameterizedItemAbstra
/** Indicated whether the action is public or internal (default <tt>true</tt>) */ /** Indicated whether the action is public or internal (default <tt>true</tt>) */
protected boolean publicAction = true; protected boolean publicAction = true;
/** List of action access restrictions (default <tt>empty list</tt> */
protected List<ActionAccessRestriction> actionAccessRestrictions = new ArrayList<>();
/** List of types and aspects for which this action is applicable */ /** List of types and aspects for which this action is applicable */
protected Set<QName> applicableTypes = new HashSet<QName>(); protected Set<QName> applicableTypes = new HashSet<QName>();
@@ -79,7 +85,7 @@ public abstract class ActionExecuterAbstractBase extends ParameterizedItemAbstra
*/ */
public void init() public void init()
{ {
if (this.publicAction == true) if (this.publicAction)
{ {
this.runtimeActionService.registerActionExecuter(this); this.runtimeActionService.registerActionExecuter(this);
} }
@@ -120,6 +126,19 @@ public abstract class ActionExecuterAbstractBase extends ParameterizedItemAbstra
this.publicAction = publicAction; this.publicAction = publicAction;
} }
/**
* Set action access restrictions
*
* @param actionAccessRestrictions
*/
public void setActionAccessRestrictions(List<ActionAccessRestriction> actionAccessRestrictions) {
this.actionAccessRestrictions = actionAccessRestrictions;
}
public List<ActionAccessRestriction> getActionAccessRestrictions() {
return actionAccessRestrictions;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@@ -270,6 +289,7 @@ public abstract class ActionExecuterAbstractBase extends ParameterizedItemAbstra
if ( !nodeIsLockedForThisUser) if ( !nodeIsLockedForThisUser)
{ {
// Execute the implementation // Execute the implementation
verifyActionAccessRestrictions(action);
executeImpl(action, actionedUponNodeRef); executeImpl(action, actionedUponNodeRef);
} }
else else
@@ -283,6 +303,13 @@ public abstract class ActionExecuterAbstractBase extends ParameterizedItemAbstra
} }
} }
/**
* {@inheritDoc}
*/
public void verifyActionAccessRestrictions(Action action) {
actionAccessRestrictions.forEach(ar -> ar.verifyAccessRestriction(action));
}
/** /**
* Execute the action implementation * Execute the action implementation
* *

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2022 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -60,6 +60,15 @@ public class CompositeActionExecuter extends ActionExecuterAbstractBase
this.actionService = actionService; this.actionService = actionService;
} }
/**
* {@inheritDoc}
*/
public void verifyActionAccessRestrictions(Action action) {
for (Action subAction : ((CompositeAction)action).getActions()) {
this.actionService.verifyActionAccessRestrictions(subAction);
}
}
/** /**
* @see org.alfresco.repo.action.executer.ActionExecuter#execute(Action, NodeRef) * @see org.alfresco.repo.action.executer.ActionExecuter#execute(Action, NodeRef)
*/ */

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2022 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -37,6 +37,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import org.alfresco.repo.action.access.ActionAccessRestriction;
import org.alfresco.repo.action.executer.ActionExecuter; import org.alfresco.repo.action.executer.ActionExecuter;
import org.alfresco.repo.forms.Field; import org.alfresco.repo.forms.Field;
import org.alfresco.repo.forms.FormData; import org.alfresco.repo.forms.FormData;
@@ -164,6 +165,7 @@ public class ActionFormProcessor extends FilteredFormProcessor<ActionDefinition,
final boolean isAsync = isAsynchronousActionRequest(item, data); final boolean isAsync = isAsynchronousActionRequest(item, data);
// execute the action // execute the action
ActionAccessRestriction.setActionContext(actionToExecute, ActionAccessRestriction.FORM_PROCESSOR_ACTION_CONTEXT);
actionService.executeAction(actionToExecute, actionedUponNodeRef, true, isAsync); actionService.executeAction(actionToExecute, actionedUponNodeRef, true, isAsync);
// extract the result // extract the result

View File

@@ -31,7 +31,6 @@ import java.util.Map;
import org.alfresco.api.AlfrescoPublicApi; import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.service.Auditable; import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
/** /**

View File

@@ -527,6 +527,7 @@
<list> <list>
<value>org.alfresco.repo.action.executer.ActionExecuter</value> <value>org.alfresco.repo.action.executer.ActionExecuter</value>
<value>org.alfresco.repo.action.executer.TestModeable</value> <value>org.alfresco.repo.action.executer.TestModeable</value>
<value>org.alfresco.repo.action.executer.LoggingAwareExecuter</value>
</list> </list>
</property> </property>
</bean> </bean>
@@ -769,4 +770,21 @@
</property> </property>
</bean> </bean>
<!-- Action Restriction Beans -->
<bean id="actionAccessRestrictionBase" abstract="true" class="org.alfresco.repo.action.access.ActionAccessRestrictionAbstractBase">
<property name="nodeService">
<ref bean="NodeService"/>
</property>
<property name="configProperties">
<ref bean="global-properties" />
</property>
</bean>
<bean id="adminActionAccessRestriction" class="org.alfresco.repo.action.access.AdminActionAccessRestriction" parent="actionAccessRestrictionBase">
<property name="authorityService">
<ref bean="AuthorityService" />
</property>
</bean>
</beans> </beans>

View File

@@ -46,7 +46,10 @@
</bean> </bean>
<bean id="mail" class="org.alfresco.repo.action.executer.MailActionExecuter" parent="action-executer"> <bean id="mail" class="org.alfresco.repo.action.executer.MailActionExecuter" parent="action-executer">
<property name="queueName" value="outboundMail"/> <property name="actionAccessRestrictions">
<ref bean="adminActionAccessRestriction"/>
</property>
<property name="queueName" value="outboundMail"/>
<property name="mailService"> <property name="mailService">
<ref bean="mailService"></ref> <ref bean="mailService"></ref>
</property> </property>

View File

@@ -5,6 +5,9 @@
<!-- This bean, which should only be used during Unit Tests, overrides the "mail" bean such that <!-- This bean, which should only be used during Unit Tests, overrides the "mail" bean such that
it sets the testMode to true. --> it sets the testMode to true. -->
<bean id="mail" class="org.alfresco.util.email.ExtendedMailActionExecutor" parent="action-executer"> <bean id="mail" class="org.alfresco.util.email.ExtendedMailActionExecutor" parent="action-executer">
<property name="actionAccessRestrictions">
<ref bean="adminActionAccessRestriction"/>
</property>
<property name="queueName" value="outboundMail"/> <property name="queueName" value="outboundMail"/>
<property name="mailService"> <property name="mailService">
<ref bean="mailService"></ref> <ref bean="mailService"></ref>