Skip to content

Commit

Permalink
Security checking for bulk actions (MID-2006) + small gui enhancements.
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Jul 29, 2014
1 parent 2c8b7f9 commit 0c66a24
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 44 deletions.
Expand Up @@ -17,11 +17,14 @@
package com.evolveum.midpoint.web.page.admin.configuration;

import com.evolveum.midpoint.model.api.ScriptExecutionException;
import com.evolveum.midpoint.model.api.ScriptExecutionResult;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
import com.evolveum.midpoint.security.api.AuthorizationConstants;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SecurityViolationException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.application.AuthorizationAction;
Expand Down Expand Up @@ -119,19 +122,22 @@ private void startPerformed(AjaxRequestTarget target) {
if (bulkActionDto.isAsync()) {
try {
getScriptingService().evaluateExpressionInBackground(expression, task, result);
} catch (SchemaException e) {
result.recordFatalError("Couldn't submit bulk action to execution because of schema exception", e);
result.recordStatus(OperationResultStatus.IN_PROGRESS, task.getName() + " has been successfully submitted to execution");
} catch (SchemaException|SecurityViolationException e) {
result.recordFatalError("Couldn't submit bulk action to execution", e);
}
} else {
try {
getScriptingService().evaluateExpression(expression, task, result);
} catch (ScriptExecutionException e) {
ScriptExecutionResult executionResult = getScriptingService().evaluateExpression(expression, task, result);
result.recordStatus(OperationResultStatus.SUCCESS, "Action executed. Returned " + executionResult.getDataOutput().size() + " item(s). Console and data output available via 'Export to XML' function.");
result.addReturn("console", executionResult.getConsoleOutput());
result.addCollectionOfSerializablesAsReturn("data", executionResult.getDataOutput());
} catch (ScriptExecutionException|SchemaException|SecurityViolationException e) {
result.recordFatalError("Couldn't execute bulk action", e);
}
}
}

result.computeStatusIfUnknown();
showResult(result);
target.add(getFeedbackPanel());
}
Expand Down
Expand Up @@ -21,9 +21,6 @@

import javax.xml.bind.JAXBElement;

import com.evolveum.midpoint.prism.util.CloneUtil;

import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.w3c.dom.Document;
Expand All @@ -37,7 +34,6 @@
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.CommonException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.EntryType;
Expand Down Expand Up @@ -674,6 +670,10 @@ public void addCollectionOfSerializablesAsParam(String paramName, Collection<? e
addParam(paramName, paramValue != null ? new ArrayList(paramValue) : null);
}

public void addCollectionOfSerializablesAsReturn(String name, Collection<? extends Serializable> value) {
addReturn(name, value != null ? new ArrayList(value) : null);
}

public void addArbitraryCollectionAsParam(String paramName, Collection values) {
if (values != null) {
ArrayList<String> valuesAsStrings = new ArrayList<String>();
Expand Down
Expand Up @@ -30,7 +30,8 @@ public enum ModelAuthorizationAction implements DisplayableValue<String> {
DISCOVER_CONNECTORS("discoverConnectors", "Discover Connectors", "DISCOVER_CONNECTORS_HELP"),

ASSIGN("assign", "Assign", "ASSIGN_HELP"),
UNASSIGN("unassign", "Unassign", "UNASSIGN_HELP");
UNASSIGN("unassign", "Unassign", "UNASSIGN_HELP"),
EXECUTE_SCRIPT("executeScript", "Execute script", "EXECUTE_SCRIPT_HELP");

private String url;
private String label;
Expand Down
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2010-2014 Evolveum
*
* 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.
*/

package com.evolveum.midpoint.model.api;

import com.evolveum.midpoint.prism.Item;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* Result of a script execution.
*
* @author mederly
*/
public class ScriptExecutionResult {

private String consoleOutput;
private List<Item> dataOutput; // unmodifiable + always non-null

public ScriptExecutionResult(String consoleOutput, List<Item> dataOutput) {
this.consoleOutput = consoleOutput;
if (dataOutput == null) {
dataOutput = new ArrayList<>();
}
this.dataOutput = Collections.unmodifiableList(dataOutput);
}

public String getConsoleOutput() {
return consoleOutput;
}

public List<Item> getDataOutput() {
return dataOutput;
}
}
Expand Up @@ -20,9 +20,9 @@
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SecurityViolationException;
import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType;

import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;

/**
Expand All @@ -46,7 +46,7 @@ public interface ScriptingService {
*
* TODO consider removing this method (it was meant as a simplified version of the method below)
*/
public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter, String actionName, Task task, OperationResult parentResult) throws SchemaException;
public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter, String actionName, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException;

/**
* Asynchronously executes any scripting expression.
Expand All @@ -59,7 +59,7 @@ public interface ScriptingService {
* @param parentResult
* @throws SchemaException
*/
public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException;
public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException;

/**
* Synchronously executes any scripting expression (with no input data).
Expand All @@ -72,5 +72,5 @@ public interface ScriptingService {
* TODO return ExecutionContext (requires moving the context to model api)
*/

public void evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException;
public ScriptExecutionResult evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException, SchemaException, SecurityViolationException;
}
Expand Up @@ -17,6 +17,8 @@

import com.evolveum.midpoint.model.api.ModelExecuteOptions;
import com.evolveum.midpoint.model.api.ModelPort;
import com.evolveum.midpoint.model.api.ScriptExecutionResult;
import com.evolveum.midpoint.model.api.ScriptingService;
import com.evolveum.midpoint.model.common.util.AbstractModelWebService;
import com.evolveum.midpoint.model.impl.controller.ModelController;
import com.evolveum.midpoint.model.impl.scripting.Data;
Expand Down Expand Up @@ -108,7 +110,7 @@ public class ModelWebService extends AbstractModelWebService implements ModelPor
private ModelController modelController;

@Autowired
private ScriptingExpressionEvaluator scriptingExpressionEvaluator;
private ScriptingService scriptingService;

@Override
public void getObject(QName objectType, String oid, SelectorQualifiedGetOptionsType optionsType,
Expand Down Expand Up @@ -273,22 +275,22 @@ private ExecuteScriptsResponseType doExecuteScripts(List<JAXBElement<?>> scripts
try {
for (JAXBElement<?> script : scriptsToExecute) {

ExecutionContext outputContext = scriptingExpressionEvaluator.evaluateExpression((ScriptingExpressionType) script.getValue(), task, result);
ScriptExecutionResult executionResult = scriptingService.evaluateExpression((ScriptingExpressionType) script.getValue(), task, result);

SingleScriptOutputType output = new SingleScriptOutputType();
outputs.getOutput().add(output);

output.setTextOutput(outputContext.getConsoleOutput());
output.setTextOutput(executionResult.getConsoleOutput());
if (options == null || options.getOutputFormat() == null || options.getOutputFormat() == OutputFormatType.XML) {
output.setXmlData(prepareXmlData(outputContext.getFinalOutput()));
output.setXmlData(prepareXmlData(executionResult.getDataOutput()));
} else {
// temporarily we send serialized XML in the case of MSL output
ItemListType jaxbOutput = prepareXmlData(outputContext.getFinalOutput());
ItemListType jaxbOutput = prepareXmlData(executionResult.getDataOutput());
output.setMslData(prismContext.serializeAnyData(jaxbOutput, SchemaConstants.C_VALUE, PrismContext.LANG_XML));
}
}
result.computeStatusIfUnknown();
} catch (ScriptExecutionException|JAXBException|SchemaException|RuntimeException e) {
} catch (ScriptExecutionException|JAXBException|SchemaException|RuntimeException|SecurityViolationException e) {
result.recordFatalError(e.getMessage(), e);
LoggingUtils.logException(LOGGER, "Exception while executing script", e);
}
Expand All @@ -297,10 +299,10 @@ private ExecuteScriptsResponseType doExecuteScripts(List<JAXBElement<?>> scripts
return response;
}

private ItemListType prepareXmlData(Data output) throws JAXBException, SchemaException {
private ItemListType prepareXmlData(List<Item> output) throws JAXBException, SchemaException {
ItemListType itemListType = new ItemListType();
if (output != null) {
for (Item item : output.getData()) {
for (Item item : output) {
RawType rawType = prismContext.toRawType(item);
itemListType.getItem().add(rawType);
}
Expand Down
Expand Up @@ -22,17 +22,17 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;

import com.evolveum.midpoint.model.api.ScriptExecutionException;
import com.evolveum.midpoint.model.api.ScriptExecutionResult;
import com.evolveum.midpoint.model.api.ScriptingService;
import com.evolveum.midpoint.model.api.TaskService;
import com.evolveum.midpoint.model.api.WorkflowService;
import com.evolveum.midpoint.model.api.hooks.ReadHook;
import com.evolveum.midpoint.model.impl.scripting.ExecutionContext;
import com.evolveum.midpoint.model.impl.scripting.ScriptingExpressionEvaluator;
import com.evolveum.midpoint.prism.parser.XNodeSerializer;
import com.evolveum.midpoint.prism.polystring.PolyString;
Expand All @@ -44,13 +44,8 @@
import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.apache.cxf.phase.Phase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import com.evolveum.midpoint.audit.api.AuditEventRecord;
Expand All @@ -61,7 +56,6 @@
import com.evolveum.midpoint.common.crypto.CryptoUtil;
import com.evolveum.midpoint.common.refinery.LayerRefinedAttributeDefinition;
import com.evolveum.midpoint.common.refinery.LayerRefinedObjectClassDefinition;
import com.evolveum.midpoint.common.refinery.LayerRefinedResourceSchema;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchema;
import com.evolveum.midpoint.model.api.ModelAuthorizationAction;
Expand Down Expand Up @@ -117,18 +111,14 @@
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultRunner;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
import com.evolveum.midpoint.schema.util.ShadowUtil;
import com.evolveum.midpoint.security.api.Authorization;
import com.evolveum.midpoint.security.api.AuthorizationConstants;
import com.evolveum.midpoint.security.api.ObjectSecurityConstraints;
import com.evolveum.midpoint.security.api.OwnerResolver;
import com.evolveum.midpoint.security.api.SecurityEnforcer;
import com.evolveum.midpoint.security.api.UserProfileService;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.task.api.TaskManager;
import com.evolveum.midpoint.util.DebugUtil;
import com.evolveum.midpoint.util.DisplayableValue;
import com.evolveum.midpoint.util.exception.CommonException;
import com.evolveum.midpoint.util.exception.CommunicationException;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.ExpressionEvaluationException;
Expand All @@ -145,7 +135,6 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorHostType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LayerType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectSynchronizationType;
Expand Down Expand Up @@ -1856,18 +1845,26 @@ public void releaseWorkItem(String workItemId, OperationResult parentResult) {

//region Scripting (bulk actions)
@Override
public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter, String actionName, Task task, OperationResult parentResult) throws SchemaException {
public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter, String actionName, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException {
checkScriptingAuthorization(parentResult);
scriptingExpressionEvaluator.evaluateExpressionInBackground(objectType, filter, actionName, task, parentResult);
}

@Override
public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException {
public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException {
checkScriptingAuthorization(parentResult);
scriptingExpressionEvaluator.evaluateExpressionInBackground(expression, task, parentResult);
}

@Override
public void evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException {
scriptingExpressionEvaluator.evaluateExpression(expression, task, result);
public ScriptExecutionResult evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException, SchemaException, SecurityViolationException {
checkScriptingAuthorization(result);
ExecutionContext executionContext = scriptingExpressionEvaluator.evaluateExpression(expression, task, result);
return executionContext.toExecutionResult();
}

private void checkScriptingAuthorization(OperationResult parentResult) throws SchemaException, SecurityViolationException {
securityEnforcer.authorize(ModelAuthorizationAction.EXECUTE_SCRIPT.getUrl(), null, null, null, null, null, parentResult);
}

//endregion
Expand Down
Expand Up @@ -16,12 +16,14 @@

package com.evolveum.midpoint.model.impl.scripting;

import com.evolveum.midpoint.model.api.ScriptExecutionResult;
import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
Expand Down Expand Up @@ -80,4 +82,13 @@ public Data getFinalOutput() {
public void setFinalOutput(Data finalOutput) {
this.finalOutput = finalOutput;
}

public ScriptExecutionResult toExecutionResult() {
List<Item> items = null;
if (getFinalOutput() != null) {
items = getFinalOutput().getData();
}
ScriptExecutionResult result = new ScriptExecutionResult(getConsoleOutput(), items);
return result;
}
}

0 comments on commit 0c66a24

Please sign in to comment.