/* Copyright 2012-2015 SAP SE * * 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 eu.aniketos.securebpmn.export.aslan.export; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.List; import org.activiti.designer.eclipse.common.ActivitiBPMNDiagramConstants; import org.activiti.designer.eclipse.extension.export.AbstractExportMarshaller; import org.activiti.designer.eclipse.extension.export.ExportMarshaller; import org.eclipse.bpmn2.ExclusiveGateway; import org.eclipse.bpmn2.ParallelGateway; import org.eclipse.bpmn2.Process; import org.eclipse.bpmn2.StartEvent; import org.eclipse.bpmn2.Task; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.emf.ecore.EObject; import org.eclipse.graphiti.mm.pictograms.Diagram; import org.eclipse.securebpmn2.BindingOfDuty; import org.eclipse.securebpmn2.Role; import org.eclipse.securebpmn2.SeparationOfDuty; import org.eclipse.securebpmn2.Subject; import org.eclipse.securebpmn2.User; import eu.aniketos.securebpmn.util.SecurityUtil; /** * Exports an ASLan representation of the diagram being saved to the workspace. * * @since 0.5.7 * @version 1 * */ public class AslanExportMarshaller extends AbstractExportMarshaller { private static final String FILENAME_PATTERN = ExportMarshaller.PLACEHOLDER_ORIGINAL_FILENAME_WITHOUT_EXTENSION + ".aslan"; private IProgressMonitor monitor; private Diagram diagram; public AslanExportMarshaller() { } /* * (non-Javadoc) * * @see org.activiti.designer.eclipse.extension.export.ExportMarshaller# * getMarshallerName() */ @Override public String getMarshallerName() { return ActivitiBPMNDiagramConstants.ASLAN_MARSHALLER_NAME; } /* * (non-Javadoc) * * @see * org.activiti.designer.eclipse.extension.export.ExportMarshaller#getFormatName * () */ @Override public String getFormatName() { return "SecureBPMN: ASLan"; } /* * (non-Javadoc) * * @see org.activiti.designer.eclipse.extension.export.ExportMarshaller# * marshallDiagram(org.eclipse.graphiti.mm.pictograms.Diagram, * org.eclipse.core.runtime.IProgressMonitor) */ @Override public void marshallDiagram(Diagram diagram, IProgressMonitor monitor) { this.monitor = monitor; this.diagram = diagram; this.monitor.beginTask("Exporting to ASLan", 100); // Clear problems for this marshaller first clearMarkers(getResource(diagram.eResource().getURI())); this.monitor.worked(10); // diagram validation // Retrieve validatorId to allow for overriding the default validator String validatorId = ActivitiBPMNDiagramConstants.ASLAN_VALIDATOR_ID; boolean validBpmn = invokeValidator(validatorId, diagram, new SubProgressMonitor(this.monitor, 10)); if (validBpmn) { marshallAslan(); } else { addProblemToDiagram( diagram, "ASLan Export skipped because SecureBPMN validation failed.", null); } this.monitor.worked(80); this.monitor.done(); } /** * Controls and executes the ASLan file generation. */ public void marshallAslan() { try { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final OutputStreamWriter osw = new OutputStreamWriter(baos, "UTF-8"); final Writer out = new BufferedWriter(osw); final List<EObject> contents = diagram.eResource().getContents(); Process process = null; for (final EObject eObject : contents) { if (eObject instanceof Process) { process = (Process) eObject; } } if (process == null) { addProblemToDiagram(diagram, "Process cannot be null", null); } final AslanFileBuilder afb = new AslanFileBuilder(out); createSignatureSection(afb); createUserRoleMappings(afb); createStaticRuleSection(afb); // element-specific content generation for (EObject object : contents) { if (object instanceof ParallelGateway) { ParallelGatewayExport.createParallelGatewayElements( (ParallelGateway) object, afb); } else if (object instanceof ExclusiveGateway) { ExclusiveGatewayExport.createExclusiveGatewayElements( (ExclusiveGateway) object, afb); } else if (object instanceof StartEvent) { final String startEventFact = "start_event_" + ((StartEvent) object).getId(); afb.addType("fact", startEventFact); afb.addInit(startEventFact); } else if (object instanceof Task) { TaskExport.createTaskElements((Task) object, afb); } else if (object instanceof SeparationOfDuty) { SeparationOfDutyExport.createSeparationOfDutyElements( (SeparationOfDuty) object, afb); } else if (object instanceof BindingOfDuty) { BindingOfDutyExport.createBindingOfDutyElements( (BindingOfDuty) object, afb); } } int writeStatus = afb.writeOutput(); out.flush(); final byte[] bytes = baos.toByteArray(); final ByteArrayInputStream bais = new ByteArrayInputStream(bytes); saveResource(getRelativeURIForDiagram(diagram, FILENAME_PATTERN), bais, new NullProgressMonitor()); if (writeStatus == AslanFileBuilder.NO_GOALS) { addWarningToDiagram( diagram, "The ASLan file contains no goals. Analyzing it with SATMC will result in an error.", null); } } catch (Exception e) { e.printStackTrace(); addProblemToDiagram( diagram, "An exception occurred while creating the ASLan file: " + e.getMessage(), null); } } /** * Writes the signature section of the ASLan file to the provided * AslanFileBuilder. * * @param afb * The AslanFileBuilder the output is sent to. */ private void createSignatureSection(AslanFileBuilder afb) { afb.addSignature("user_to_role : user * role -> fact"); afb.addSignature("poto : userORrole * taskName -> fact"); afb.addSignature("task_to_data : taskName * set * set -> fact"); afb.addSignature("aknows : entity * data -> fact"); afb.addSignature("mc_pair : data * data -> data"); afb.addSignature("contains : set * data -> fact"); afb.addSignature("task : taskName * nat -> taskInstance"); afb.addSignature("canExecute : user * role * humanTaskName -> fact"); afb.addSignature("granted : user * role * taskInstance -> fact"); afb.addSignature("executed : user * taskInstance -> fact"); afb.addSignature("ready : taskInstance -> fact"); afb.addSignature("done : taskInstance -> fact"); afb.addSignature("entity > organization"); afb.addSignature("entity > user"); afb.addSignature("data > object"); afb.addSignature("data > set"); afb.addSignature("userORrole > user"); afb.addSignature("userORrole > role"); afb.addSignature("taskName > automatedTaskName"); afb.addSignature("taskName > humanTaskName"); } /** * Writes the static rules of the ASLan file to the provided * AslanFileBuilder. * * @param afb * The AslanFileBuilder the output is sent to. */ private void createStaticRuleSection(AslanFileBuilder afb) { // variable type definitions afb.addType("user", "A"); afb.addType("role", "R"); afb.addType("humanTaskName", "HT"); afb.addType("nat", "N"); afb.addType("set", "IN"); afb.addType("set", "OUT"); afb.addType("automatedTaskName", "AT"); // task claiming authorization afb.addHornClause("hc rbac_ac (A,R,HT) := canExecute(A,R,HT) :- user_to_role(A,R), poto(R,HT)"); afb.addHornClause("hc direct_ac (A,R,HT) := canExecute(A,R,HT) :- user_to_role(A,R), poto(A,HT)"); // task claiming afb.addRule("step authorizeTaskExecution(A,R,HT,N) := canExecute(A,R,HT). ready(task(HT,N)) => granted(A,R,task(HT,N))"); // human task execution afb.addRule("step h_taskExecution(A,R,HT,N,IN,OUT) := granted(A,R,task(HT,N)). task_to_data(HT,IN,OUT) => executed(A,task(HT,N)). done(task(HT,N)). task_to_data(HT,IN,OUT). aknows(A,IN). aknows(A,OUT)"); // automated task execution afb.addRule("step atask_execution(AT,N,IN,OUT) := ready(task(AT,N)). task_to_data(AT,IN,OUT) => done(task(AT,N)). task_to_data(AT,IN,OUT)"); } /** * Writes the user to role mappings of the ASLan file to the provided * AslanFileBuilder. * * @param afb * The AslanFileBuilder the output is sent to. */ private void createUserRoleMappings(AslanFileBuilder afb) { final List<Role> roles = SecurityUtil.getRoles(diagram); for (Role r : roles) { final String roleName = r.getName().toLowerCase(); afb.addType("role", roleName); for (Subject s : r.getSubjects()) { if (s instanceof User) { final User u = (User) s; final String userName = u.getUserName().toLowerCase(); afb.addType("user", userName); afb.addInit("user_to_role(" + userName + "," + roleName + ")"); } } } } }