mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
[MNT-24913] Added fallback method to obtain deployment category in order to check if workflow is secure (#3236)
This commit is contained in:
@@ -28,11 +28,17 @@ package org.alfresco.repo.workflow.activiti.script;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.activiti.engine.RepositoryService;
|
||||
import org.activiti.engine.delegate.VariableScope;
|
||||
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.activiti.engine.impl.context.Context;
|
||||
import org.activiti.engine.impl.el.Expression;
|
||||
import org.activiti.engine.impl.persistence.entity.DeploymentEntity;
|
||||
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
|
||||
import org.activiti.engine.repository.ProcessDefinition;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.workflow.WorkflowDeployer;
|
||||
@@ -45,13 +51,12 @@ import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowException;
|
||||
|
||||
/**
|
||||
* Base class for execution scripts, using {@link ScriptService} as part of
|
||||
* activiti workflow.
|
||||
* Base class for execution scripts, using {@link ScriptService} as part of activiti workflow.
|
||||
*
|
||||
* @author Frederik Heremans
|
||||
* @since 3.4.e
|
||||
*/
|
||||
public class ActivitiScriptBase
|
||||
public class ActivitiScriptBase
|
||||
{
|
||||
protected static final String PERSON_BINDING_NAME = "person";
|
||||
protected static final String USERHOME_BINDING_NAME = "userhome";
|
||||
@@ -61,17 +66,19 @@ public class ActivitiScriptBase
|
||||
protected Expression runAs;
|
||||
protected Expression scriptProcessor;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ActivitiScriptBase.class);
|
||||
|
||||
protected Object executeScript(String theScript, Map<String, Object> model, String scriptProcessorName, String runAsUser)
|
||||
{
|
||||
String user = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
|
||||
|
||||
Object scriptResult = null;
|
||||
if (runAsUser == null && user != null)
|
||||
{
|
||||
// Just execute the script using the current user
|
||||
scriptResult = executeScript(theScript, model, scriptProcessorName);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if (runAsUser != null)
|
||||
{
|
||||
@@ -87,26 +94,25 @@ public class ActivitiScriptBase
|
||||
}
|
||||
return scriptResult;
|
||||
}
|
||||
|
||||
|
||||
protected Object executeScriptAsUser(final String theScript, final Map<String, Object> model, final String scriptProcessorName, final String runAsUser)
|
||||
{
|
||||
// execute as specified runAsUser
|
||||
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
|
||||
{
|
||||
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<>() {
|
||||
public Object doWork() throws Exception
|
||||
{
|
||||
return executeScript(theScript, model, scriptProcessorName);
|
||||
}
|
||||
}, runAsUser);
|
||||
}
|
||||
|
||||
|
||||
protected Object executeScript(String theScript, Map<String, Object> model, String scriptProcessorName)
|
||||
{
|
||||
// Execute the script using the appropriate processor
|
||||
Object scriptResult = null;
|
||||
|
||||
// Checks if current workflow is secure
|
||||
boolean secure = isSecure();
|
||||
boolean secure = isSecure(model);
|
||||
|
||||
if (scriptProcessorName != null)
|
||||
{
|
||||
@@ -117,11 +123,11 @@ public class ActivitiScriptBase
|
||||
// Use default script-processor
|
||||
scriptResult = getServiceRegistry().getScriptService().executeScriptString(theScript, model, secure);
|
||||
}
|
||||
|
||||
|
||||
return scriptResult;
|
||||
}
|
||||
|
||||
protected String getStringValue(Expression expression, VariableScope scope)
|
||||
|
||||
protected String getStringValue(Expression expression, VariableScope scope)
|
||||
{
|
||||
if (expression != null)
|
||||
{
|
||||
@@ -133,15 +139,15 @@ public class ActivitiScriptBase
|
||||
protected ServiceRegistry getServiceRegistry()
|
||||
{
|
||||
ProcessEngineConfigurationImpl config = Context.getProcessEngineConfiguration();
|
||||
if (config != null)
|
||||
if (config != null)
|
||||
{
|
||||
// Fetch the registry that is injected in the activiti spring-configuration
|
||||
ServiceRegistry registry = (ServiceRegistry) config.getBeans().get(ActivitiConstants.SERVICE_REGISTRY_BEAN_KEY);
|
||||
if (registry == null)
|
||||
{
|
||||
throw new RuntimeException(
|
||||
"Service-registry not present in ProcessEngineConfiguration beans, expected ServiceRegistry with key" +
|
||||
ActivitiConstants.SERVICE_REGISTRY_BEAN_KEY);
|
||||
"Service-registry not present in ProcessEngineConfiguration beans, expected ServiceRegistry with key" +
|
||||
ActivitiConstants.SERVICE_REGISTRY_BEAN_KEY);
|
||||
}
|
||||
return registry;
|
||||
}
|
||||
@@ -149,42 +155,136 @@ public class ActivitiScriptBase
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the workflow must be considered secure or not - based on {@link DeploymentEntity} category.
|
||||
* If it is not considered secure, the workflow will be executed in sandbox context with more restrictions
|
||||
* Checks whether the workflow must be considered secure or not - based on {@link DeploymentEntity} category. If it is not considered secure, the workflow will be executed in sandbox context with more restrictions
|
||||
*
|
||||
* @return true if workflow is considered secure, false otherwise
|
||||
*/
|
||||
private boolean isSecure()
|
||||
private boolean isSecure(Map<String, Object> model)
|
||||
{
|
||||
String category = getDeploymentCategory(model);
|
||||
|
||||
// iF The deployment category matches the condition (either internal or full access) the workflow is considered secure
|
||||
return category != null && (WorkflowDeployer.CATEGORY_ALFRESCO_INTERNAL.equals(category) || WorkflowDeployer.CATEGORY_FULL_ACCESS.equals(category));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the deployment category from the execution context. If no execution context is available, a query to obtain the deployment is performed so the category can be returned.
|
||||
*
|
||||
* @param model
|
||||
* a map with workflow model
|
||||
* @return the deployment category
|
||||
*/
|
||||
private String getDeploymentCategory(Map<String, Object> model)
|
||||
{
|
||||
String category = getDeploymentCategoryFromContext();
|
||||
|
||||
if (category == null)
|
||||
{
|
||||
String deploymentId = null;
|
||||
String processDefinitionId = null;
|
||||
|
||||
if (model != null && model.containsKey(EXECUTION_BINDING_NAME) && model.get(EXECUTION_BINDING_NAME) instanceof ExecutionEntity)
|
||||
{
|
||||
ExecutionEntity executionEntity = (ExecutionEntity) model.get(EXECUTION_BINDING_NAME);
|
||||
deploymentId = executionEntity.getDeploymentId();
|
||||
processDefinitionId = executionEntity.getProcessDefinitionId();
|
||||
}
|
||||
|
||||
category = getDeploymentCategoryFromQuery(deploymentId, processDefinitionId);
|
||||
}
|
||||
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the deployment category from current execution context
|
||||
*
|
||||
* @return the category for current execution deployment, otherwise null
|
||||
*/
|
||||
private String getDeploymentCategoryFromContext()
|
||||
{
|
||||
String category = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (Context.isExecutionContextActive())
|
||||
{
|
||||
category = Context.getExecutionContext().getDeployment().getCategory();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("No execution context available");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// No action required
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("Could not obtain deployment category from execution context: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// If the workflow is considered secure, the deployment entity category matches the condition (either internal or full access)
|
||||
return category != null && (WorkflowDeployer.CATEGORY_ALFRESCO_INTERNAL.equals(category) || WorkflowDeployer.CATEGORY_FULL_ACCESS.equals(category));
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the specified 'runAs' field
|
||||
* specifies a valid username.
|
||||
* Obtains the deployment category through a query
|
||||
*
|
||||
* @param deploymentId
|
||||
* the deployment id to obtain the category from
|
||||
* @param processDefinitionId
|
||||
* if no deployment id is provided, the process definition id can be used to obtain the deployment
|
||||
* @return the category for the obtained deployment, otherwise null
|
||||
*/
|
||||
private void validateRunAsUser(final String runAsUser)
|
||||
private String getDeploymentCategoryFromQuery(String deploymentId, String processDefinitionId)
|
||||
{
|
||||
Boolean runAsExists = AuthenticationUtil.runAs(new RunAsWork<Boolean>()
|
||||
String category = null;
|
||||
|
||||
try
|
||||
{
|
||||
RepositoryService repositoryService = Context.getProcessEngineConfiguration().getRepositoryService();
|
||||
|
||||
if (deploymentId == null && processDefinitionId != null)
|
||||
{
|
||||
ProcessDefinition processDefnition = repositoryService.getProcessDefinition(processDefinitionId);
|
||||
if (processDefnition != null)
|
||||
{
|
||||
deploymentId = processDefnition.getDeploymentId();
|
||||
}
|
||||
}
|
||||
|
||||
if (deploymentId != null)
|
||||
{
|
||||
DeploymentEntity deployment = (DeploymentEntity) repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
|
||||
if (deployment != null)
|
||||
{
|
||||
category = deployment.getCategory();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("Could not obtain deployment category through a query: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the specified 'runAs' field specifies a valid username.
|
||||
*/
|
||||
private void validateRunAsUser(final String runAsUser)
|
||||
{
|
||||
Boolean runAsExists = AuthenticationUtil.runAs(new RunAsWork<>() {
|
||||
// Validate using System user to ensure sufficient permissions available to access person node.
|
||||
|
||||
public Boolean doWork() throws Exception
|
||||
@Override
|
||||
public Boolean doWork() throws Exception
|
||||
{
|
||||
return getServiceRegistry().getPersonService().personExists(runAsUser);
|
||||
}
|
||||
@@ -195,21 +295,21 @@ public class ActivitiScriptBase
|
||||
throw new WorkflowException("runas user '" + runAsUser + "' does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected ActivitiScriptNode getPersonNode(String runAsUser)
|
||||
{
|
||||
String userName = null;
|
||||
if (runAsUser != null)
|
||||
if (runAsUser != null)
|
||||
{
|
||||
userName = runAsUser;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
userName = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
}
|
||||
|
||||
|
||||
// The "System" user is a special case, which has no person object associated with it.
|
||||
if(userName != null && !AuthenticationUtil.SYSTEM_USER_NAME.equals(userName))
|
||||
if (userName != null && !AuthenticationUtil.SYSTEM_USER_NAME.equals(userName))
|
||||
{
|
||||
ServiceRegistry services = getServiceRegistry();
|
||||
PersonService personService = services.getPersonService();
|
||||
@@ -221,18 +321,18 @@ public class ActivitiScriptBase
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setScript(Expression script)
|
||||
|
||||
public void setScript(Expression script)
|
||||
{
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
public void setRunAs(Expression runAs)
|
||||
public void setRunAs(Expression runAs)
|
||||
{
|
||||
this.runAs = runAs;
|
||||
}
|
||||
|
||||
public void setScriptProcessor(Expression scriptProcessor)
|
||||
public void setScriptProcessor(Expression scriptProcessor)
|
||||
{
|
||||
this.scriptProcessor = scriptProcessor;
|
||||
}
|
||||
|
Reference in New Issue
Block a user