getCtx() {
+ return Collections.unmodifiableMap(ctxData);
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParser.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParser.java
new file mode 100644
index 000000000..b38bb7aa0
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParser.java
@@ -0,0 +1,224 @@
+package at.gv.egovernment.moa.id.process;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import javax.xml.stream.util.EventReaderDelegate;
+import javax.xml.transform.stax.StAXSource;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+import com.datentechnik.process_engine.model.EndEvent;
+import com.datentechnik.process_engine.model.ProcessDefinition;
+import com.datentechnik.process_engine.model.ProcessNode;
+import com.datentechnik.process_engine.model.StartEvent;
+import com.datentechnik.process_engine.model.TaskInfo;
+import com.datentechnik.process_engine.model.Transition;
+
+/**
+ * Parses an XML representation of a process definition as defined by the respective XML schema.
+ * transitionElements = new ArrayList<>();
+ final List startEvents = new ArrayList<>();
+
+ reader = new EventReaderDelegate(reader) {
+
+ @Override
+ public XMLEvent nextEvent() throws XMLStreamException {
+ XMLEvent event = super.nextEvent();
+
+ switch (event.getEventType()) {
+ case XMLStreamConstants.START_ELEMENT:
+ StartElement element = event.asStartElement();
+ QName qname = element.getName();
+
+ if (NS.equals(qname.getNamespaceURI())) {
+ log.trace("Found process description element '{}'.", qname.getLocalPart());
+ Attribute id = element.getAttributeByName(new QName("id"));
+
+ switch (qname.getLocalPart()) {
+ case "ProcessDefinition":
+ if (id != null) {
+ pd.setId(id.getValue());
+ }
+ break;
+ case "StartEvent":
+ StartEvent startEvent = new StartEvent();
+ if (id != null) {
+ startEvent.setId(id.getValue());
+ }
+ startEvents.add(startEvent);
+ break;
+ case "EndEvent":
+ EndEvent endEvent = new EndEvent();
+ if (id != null) {
+ endEvent.setId(id.getValue());
+ pd.getEndEvents().put(id.getValue(), endEvent);
+ }
+ break;
+ case "Transition":
+ transitionElements.add(element);
+ break;
+ case "Task":
+ TaskInfo taskInfo = new TaskInfo();
+ if (id != null) {
+ taskInfo.setId(id.getValue());
+ pd.getTaskInfos().put(id.getValue(), taskInfo);
+ }
+ Attribute async = element.getAttributeByName(new QName("async"));
+ if (async != null) {
+ taskInfo.setAsync(Boolean.valueOf(async.getValue()));
+ }
+ Attribute implementingClass = element.getAttributeByName(new QName("class"));
+ if (implementingClass != null) {
+ taskInfo.setTaskImplementingClass(implementingClass.getValue());
+ }
+ break;
+ }
+
+ }
+
+ break;
+ }
+
+ return event;
+ }
+
+ };
+
+ // validator is not thread-safe
+ Validator validator = LazyProcessDefinitionSchemaHolder.PD_SCHEMA_INSTANCE.newValidator();
+ validator.validate(new StAXSource(reader));
+ log.trace("Process definition successfully schema validated.");
+
+ // perform some basic checks
+ log.trace("Building model and performing some plausibility checks.");
+ if (startEvents.size() != 1) {
+ throw new ProcessDefinitionParserException("A ProcessDefinition must contain exactly one single StartEvent.");
+ }
+ pd.setStartEvent(startEvents.get(0));
+
+ // link transitions
+ Iterator transitions = transitionElements.iterator();
+ while (transitions.hasNext()) {
+ StartElement element = transitions.next();
+ Transition transition = new Transition();
+ Attribute id = element.getAttributeByName(new QName("id"));
+ if (id != null) {
+ transition.setId(id.getValue());
+ }
+ Attribute conditionExpression = element.getAttributeByName(new QName("conditionExpression"));
+ if (conditionExpression != null) {
+ transition.setConditionExpression(conditionExpression.getValue());
+ }
+ Attribute from = element.getAttributeByName(new QName("from"));
+ if (from != null) {
+ ProcessNode fromNode = pd.getProcessNode(from.getValue());
+ if (fromNode == null) {
+ throw new ProcessDefinitionParserException("Transition's 'from'-attribute refers to a non-existing event or task '" + from.getValue() + '.');
+ }
+ if (fromNode instanceof EndEvent) {
+ throw new ProcessDefinitionParserException("Transition cannot start from end event.");
+ }
+ transition.setFrom(fromNode);
+ fromNode.getOutgoingTransitions().add(transition);
+ }
+ Attribute to = element.getAttributeByName(new QName("to"));
+ if (to != null) {
+ ProcessNode toNode = pd.getProcessNode(to.getValue());
+ if (toNode == null) {
+ throw new ProcessDefinitionParserException("Transition's 'to'-attribute refers to a non-existing event or task '" + to.getValue() + '.');
+ }
+ transition.setTo(toNode);
+ toNode.getIncomingTransitions().add(transition);
+ }
+ if (transition.getConditionExpression() == null && Objects.equals(transition.getFrom(), transition.getTo())) {
+ throw new ProcessDefinitionParserException("Transition's 'from' equals its 'to'. Since no 'conditionExpression' has been set this will cause a loop.");
+ }
+ }
+ log.debug("Process definition '{}' successfully parsed.", pd.getId());
+ return pd;
+
+ } catch (ProcessDefinitionParserException e) {
+ throw e;
+ } catch (XMLStreamException|IOException e) {
+ throw new ProcessDefinitionParserException("Unable to read process definition from inputstream.", e);
+ } catch (SAXException e) {
+ throw new ProcessDefinitionParserException("Schema validation of process description failed.", e);
+ } catch (Exception e) {
+ throw new ProcessDefinitionParserException("Internal error creating process definition from inputstream.", e);
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (XMLStreamException e) {
+ // error freeing resources
+ }
+ }
+ }
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParserException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParserException.java
new file mode 100644
index 000000000..0c214750d
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessDefinitionParserException.java
@@ -0,0 +1,35 @@
+package at.gv.egovernment.moa.id.process;
+
+/**
+ * Exception thrown in case of error parsing a process definition.
+ *
+ * @author tknall
+ *
+ */
+public class ProcessDefinitionParserException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new parser exception providing a {@code message} describing the reason and the {@code cause}.
+ *
+ * @param message
+ * The message.
+ * @param cause
+ * The cause.
+ */
+ public ProcessDefinitionParserException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new parser exception providing a {@code message} describing the reason.
+ *
+ * @param message
+ * The message.
+ */
+ public ProcessDefinitionParserException(String message) {
+ super(message);
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngine.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngine.java
new file mode 100644
index 000000000..b4135ee41
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngine.java
@@ -0,0 +1,113 @@
+package at.gv.egovernment.moa.id.process;
+
+
+import java.io.InputStream;
+import java.io.Serializable;
+
+import com.datentechnik.process_engine.api.ExecutionContext;
+import com.datentechnik.process_engine.model.ProcessDefinition;
+
+/**
+ * Process engine providing means for starting and resuming processes.
+ *
+ * @author tknall
+ */
+public interface ProcessEngine {
+
+ /**
+ * Registers a new process definition. Note that existing definitions with the same identifier will be replaced.
+ *
+ * @param processDefinition
+ * The process definition to be registered.
+ */
+ void registerProcessDefinition(ProcessDefinition processDefinition);
+
+ /**
+ * Registers a new process definition given as {@link InputStream}. Note that existing definitions with the same identifier will be replaced.
+ *
+ * @param processDefinitionInputStream The input stream to the definition to be registered.
+ * @throws ProcessDefinitionParserException Thrown in case of an error parsing the process definition.
+ */
+ void registerProcessDefinition(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException;
+
+ /**
+ * Creates a process instance according to the referenced process definition.
+ *
+ * Note that the method returns a process instance which will be needed in order to start a process or to continue
+ * process execution after asynchronous task execution (refer to {@link #start(ProcessInstance)} and
+ * {@link #signal(ProcessInstance)} for further information).
+ *
+ * @param processDefinitionId
+ * The identifier of the respective process definition.
+ * @param executionContext The execution context (may be {@code null}).
+ * @return The newly created process instance (never {@code null}).
+ * @throws ProcessExecutionException
+ * Thrown in case of error, e.g. when a {@code processDefinitionId} is referenced that does not exist.
+ */
+ ProcessInstance createProcessInstance(String processDefinitionId, ExecutionContext executionContext) throws ProcessExecutionException;
+
+ /**
+ * Creates a process instance according to the referenced process definition.
+ *
+ * Note that the method returns a process instance which will be needed in order to start a process or to continue
+ * process execution after asynchronous task execution (refer to {@link #start(ProcessInstance)} and
+ * {@link #signal(ProcessInstance)} for further information).
+ *
+ * @param processDefinitionId
+ * The identifier of the respective process definition.
+ * @return The newly created process instance (never {@code null}).
+ * @throws ProcessExecutionException
+ * Thrown in case of error, e.g. when a {@code processDefinitionId} is referenced that does not exist.
+ */
+ ProcessInstance createProcessInstance(String processDefinitionId) throws ProcessExecutionException;
+
+ /**
+ * Returns the process instance with a given {@code processInstanceId}.
+ *
+ * @param processInstanceId
+ * The process instance id.
+ * @return The process instance (never {@code null}).
+ * @throws IllegalArgumentException
+ * In case the process instance does not/no longer exist.
+ */
+ ProcessInstance getProcessInstance(String processInstanceId);
+
+ /**
+ * Starts the process using the given {@code processInstance}.
+ *
+ * @param processInstance
+ * The process instance.
+ * @throws ProcessExecutionException
+ * Thrown in case of error.
+ */
+ void start(ProcessInstance processInstance) throws ProcessExecutionException;
+
+ /**
+ * Resumes process execution after an asynchronous task has been executed.
+ *
+ * @param processInstance
+ * The process instance.
+ * @throws ProcessExecutionException
+ * Thrown in case of error.
+ */
+ void signal(ProcessInstance processInstance) throws ProcessExecutionException;
+
+ /**
+ * Performs cleanup, removing all process instances that have not been used for a certain time.
+ *
+ * @see #setProcessInstanceMaxIdleTimeSeconds(long)
+ */
+ void cleanup();
+
+ /**
+ * Returns the first process instance with a process context containing some {@code value} stored under key {@code key}.
+ *
+ * @param key
+ * The key.
+ * @param value
+ * The value that needs to match.
+ * @return The process instance or {@code null} in case no process instance was found.
+ */
+ ProcessInstance findProcessInstanceWith(String key, Serializable value);
+
+}
\ No newline at end of file
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngineImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngineImpl.java
new file mode 100644
index 000000000..8f9d73b3d
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngineImpl.java
@@ -0,0 +1,304 @@
+package at.gv.egovernment.moa.id.process;
+
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+
+import com.datentechnik.process_engine.api.ExecutionContext;
+import com.datentechnik.process_engine.api.ExpressionEvaluationContext;
+import com.datentechnik.process_engine.api.ExpressionEvaluator;
+import com.datentechnik.process_engine.api.Task;
+import com.datentechnik.process_engine.model.EndEvent;
+import com.datentechnik.process_engine.model.ProcessDefinition;
+import com.datentechnik.process_engine.model.ProcessNode;
+import com.datentechnik.process_engine.model.StartEvent;
+import com.datentechnik.process_engine.model.TaskInfo;
+import com.datentechnik.process_engine.model.Transition;
+
+/**
+ * Process engine implementation allowing starting and continuing processes as well as providing means for cleanup actions.
+ * @author tknall
+ *
+ */
+public class ProcessEngineImpl implements ProcessEngine {
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+ private ProcessDefinitionParser pdp = new ProcessDefinitionParser();
+
+ private Map processDefinitions = new ConcurrentHashMap();
+ private Map processInstances = new ConcurrentHashMap();
+
+ private final static String MDC_CTX_PI_NAME = "processInstanceId";
+ private final static String MDC_CTX_TASK_NAME = "taskId";
+
+ private static final long DEFAULT_PROCESS_INSTANCE_MAX_AGE_SECONDS = 3600;
+ private long processInstanceIdleTimeSeconds = DEFAULT_PROCESS_INSTANCE_MAX_AGE_SECONDS;
+ private ExpressionEvaluator transitionConditionExpressionEvaluator;
+
+ @Override
+ public void registerProcessDefinition(ProcessDefinition processDefinition) {
+ log.info("Registering process definition '{}'.", processDefinition.getId());
+ processDefinitions.put(processDefinition.getId(), processDefinition);
+ }
+
+ @Override
+ public void registerProcessDefinition(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException{
+ registerProcessDefinition(pdp.parse(processDefinitionInputStream));
+ }
+
+ /**
+ * Sets the process definitions.
+ *
+ * @param processDefinitions
+ * The process definitions.
+ * @throws IllegalArgumentException
+ * In case the process definitions contain definitions with the same identifier.
+ */
+ public void setProcessDefinitions(Iterable processDefinitions) {
+ this.processDefinitions.clear();
+ for (ProcessDefinition pd : processDefinitions) {
+ if (this.processDefinitions.containsKey(pd.getId())) {
+ throw new IllegalArgumentException("Duplicate process definition identifier '" + pd.getId() + "'.");
+ }
+ registerProcessDefinition(pd);
+ }
+ }
+
+ /**
+ * Defines the time frame in seconds an idle process instance will be managed by the process engine. A process
+ * instance with an idle time larger than the given time will be removed.
+ *
+ * Note that {@link #cleanup()} needs to be called in order to remove expired process instances.
+ *
+ * @param processInstanceMaxIdleTimeSeconds
+ * The maximum idle time in seconds.
+ */
+ public void setProcessInstanceMaxIdleTimeSeconds(long processInstanceMaxIdleTimeSeconds) {
+ this.processInstanceIdleTimeSeconds = processInstanceMaxIdleTimeSeconds;
+ }
+
+ /**
+ * Sets an expression evaluator that should be used to process transition condition expressions.
+ * @param transitionConditionExpressionEvaluator The expression evaluator.
+ */
+ public void setTransitionConditionExpressionEvaluator(
+ ExpressionEvaluator transitionConditionExpressionEvaluator) {
+ this.transitionConditionExpressionEvaluator = transitionConditionExpressionEvaluator;
+ }
+
+
+ @Override
+ public ProcessInstance createProcessInstance(String processDefinitionId, ExecutionContext executionContext) throws ProcessExecutionException {
+ // look for respective process definition
+ ProcessDefinition pd = processDefinitions.get(processDefinitionId);
+ if (pd == null) {
+ throw new ProcessExecutionException("Unable to find process definition for process '" + processDefinitionId + "'.");
+ }
+ // create and keep process instance
+ ProcessInstance pi = new ProcessInstance(pd, executionContext);
+ log.info("Creating process instance from process definition '{}': {}", processDefinitionId, pi.getId());
+ processInstances.put(pi.getId(), pi);
+ return pi;
+ }
+
+ @Override
+ public ProcessInstance createProcessInstance(String processDefinitionId) throws ProcessExecutionException {
+ return createProcessInstance(processDefinitionId, null);
+ }
+
+ @Override
+ public void start(ProcessInstance pi) throws ProcessExecutionException {
+ MDC.put(MDC_CTX_PI_NAME, pi.getId());
+ try {
+ if (!ProcessInstanceState.NOT_STARTED.equals(pi.getState())) {
+ throw new ProcessExecutionException("Process instance '" + pi.getId() + "' has already been started (current state is " + pi.getState() + ").");
+ }
+ log.info("Starting process instance '{}'.", pi.getId());
+ // execute process
+ pi.setState(ProcessInstanceState.STARTED);
+ execute(pi);
+ } finally {
+ MDC.remove(MDC_CTX_PI_NAME);
+ }
+ }
+
+ @Override
+ public void signal(ProcessInstance pi) throws ProcessExecutionException {
+ MDC.put(MDC_CTX_PI_NAME, pi.getId());
+ try {
+ if (!ProcessInstanceState.SUSPENDED.equals(pi.getState())) {
+ throw new ProcessExecutionException("Process instance '" + pi.getId() + "' has not been suspended (current state is " + pi.getState() + ").");
+ }
+ log.info("Waking up process instance '{}'.", pi.getId());
+ pi.setState(ProcessInstanceState.STARTED);
+ execute(pi);
+ } finally {
+ MDC.remove(MDC_CTX_PI_NAME);
+ }
+ }
+
+ @Override
+ public synchronized void cleanup() {
+ log.trace("Cleanup job started.");
+ Iterator> it = processInstances.entrySet().iterator();
+ while (it.hasNext()) {
+ Entry entry = it.next();
+ ProcessInstance pi = entry.getValue();
+ log.trace("Checking process instance {}.", pi);
+ long ageMillis = new Date().getTime() - pi.getLru().getTime();
+ if (ageMillis > processInstanceIdleTimeSeconds * 1000) {
+ log.info("Removing process instance '{}'.", pi.getId());
+ processInstances.remove(entry.getKey());
+ }
+ }
+ log.trace("Cleanup job completed.");
+ }
+
+ /**
+ * Instantates a task implementation given by a {@link TaskInfo}.
+ * @param ti The task info.
+ * @return A Task implementation or {@code null} if the task info does not reference any task implementing classes.
+ * @throws ProcessExecutionException Thrown in case of error (when the referenced class does not implement {@link Task} for instance).
+ */
+ private Task createTaskInstance(TaskInfo ti) throws ProcessExecutionException {
+ String clazz = StringUtils.trimToNull(ti.getTaskImplementingClass());
+ Task task = null;
+
+ if (clazz != null) {
+ log.debug("Instantiating task implementing class '{}'.", clazz);
+ Class> instanceClass = null;
+ try {
+ instanceClass = Class.forName(clazz, true, Thread.currentThread().getContextClassLoader());
+ } catch (Exception e) {
+ throw new ProcessExecutionException("Unable to get class '" + clazz + "' associated with task '" + ti.getId() + "' .", e);
+ }
+ if (!Task.class.isAssignableFrom(instanceClass)) {
+ throw new ProcessExecutionException("Class '" + clazz + "' associated with task '" + ti.getId() + "' is not assignable to " + Task.class.getName() + ".");
+ }
+ try {
+ task = (Task) instanceClass.newInstance();
+ } catch (Exception e) {
+ throw new ProcessExecutionException("Unable to instantiate class '" + clazz + "' associated with task '" + ti.getId() + "' .", e);
+ }
+ }
+
+ return task;
+ }
+
+ /**
+ * Starts/executes a given process instance.
+ * @param pi The process instance.
+ * @throws ProcessExecutionException Thrown in case of error.
+ */
+ private void execute(final ProcessInstance pi) throws ProcessExecutionException {
+ if (ProcessInstanceState.ENDED.equals(pi.getState())) {
+ throw new ProcessExecutionException("Process for instance '" + pi.getId() + "' has already been ended.");
+ }
+ ProcessDefinition pd = pi.getProcessDefinition();
+ ProcessNode processNode = pd.getProcessNode(pi.getNextId());
+ log.debug("Processing node '{}'.", processNode.getId());
+
+ // distinguish process node types StartEvent, TaskInfo and EndEvent
+
+ if (processNode instanceof TaskInfo) {
+ // TaskInfo types need to be executed
+ TaskInfo ti = (TaskInfo) processNode;
+ MDC.put(MDC_CTX_TASK_NAME, ti.getId());
+ try {
+ log.info("Processing task '{}'.", ti.getId());
+ Task task = createTaskInstance(ti);
+ if (task != null) {
+ try {
+ log.info("Executing task implementation for task '{}'.", ti.getId());
+ log.debug("Execution context before task execution: {}", pi.getExecutionContext().keySet());
+ task.execute(pi.getExecutionContext());
+ log.info("Returned from execution of task '{}'.", ti.getId());
+ log.debug("Execution context after task execution: {}", pi.getExecutionContext().keySet());
+ } catch (Throwable t) {
+ throw new ProcessExecutionException("Error executing task '" + ti.getId() + "'.", t);
+ }
+ } else {
+ log.debug("No task implementing class set.");
+ }
+ } finally {
+ MDC.remove(MDC_CTX_TASK_NAME);
+ }
+
+ } else if (processNode instanceof EndEvent) {
+ log.info("Finishing process instance '{}'.", pi.getId());
+ processInstances.remove(pi.getId());
+ pi.setState(ProcessInstanceState.ENDED);
+ log.debug("Final process context: {}", pi.getExecutionContext().keySet());
+ return;
+ }
+
+ final ExpressionEvaluationContext expressionContext = new ExpressionEvaluationContextImpl(pi);
+
+ // traverse pointer
+ Transition t = CollectionUtils.find(processNode.getOutgoingTransitions(), new Predicate() {
+ @Override
+ public boolean evaluate(Transition transition) {
+ if (transitionConditionExpressionEvaluator != null && transition.getConditionExpression() != null) {
+ log.trace("Evaluating transition expression '{}'.", transition.getConditionExpression());
+ return transitionConditionExpressionEvaluator.evaluate(expressionContext, transition.getConditionExpression());
+ }
+ return true;
+ }
+ });
+ if (t == null) {
+ throw new ProcessExecutionException("No valid transition starting from process node '" + processNode.getId()+ "'.");
+ }
+ log.trace("Found suitable transition: {}", t);
+ // update pointer
+ log.trace("Shifting process token from '{}' to '{}'.", pi.getNextId(), t.getTo().getId());
+ pi.setNextId(t.getTo().getId());
+
+ // inspect current task
+ if (t.getTo() instanceof TaskInfo && (((TaskInfo) t.getTo()).isAsync())) {
+ // immediately return in case of asynchonous task
+ log.info("Suspending process instance '{}' for asynchronous task '{}'.", pi.getId(), t.getTo().getId());
+ pi.setState(ProcessInstanceState.SUSPENDED);
+ return;
+ }
+
+ // continue execution in case of StartEvent or Task
+ if (processNode instanceof StartEvent || processNode instanceof TaskInfo) {
+ execute(pi);
+ }
+ }
+
+ @Override
+ public ProcessInstance getProcessInstance(String processInstanceId) {
+ ProcessInstance processInstance = processInstances.get(processInstanceId);
+ if (processInstance == null) {
+ throw new IllegalArgumentException("The process instance '" + processInstanceId + "' does not/no longer exist.");
+ }
+ return processInstance;
+ }
+
+ @Override
+ public ProcessInstance findProcessInstanceWith(String key, Serializable value) {
+ Iterator it = processInstances.values().iterator();
+ while (it.hasNext()) {
+ ProcessInstance pi = it.next();
+ if (Objects.equals(pi.getExecutionContext().get(key), value)) {
+ return pi;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessExecutionException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessExecutionException.java
new file mode 100644
index 000000000..821bbe6dc
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessExecutionException.java
@@ -0,0 +1,36 @@
+package at.gv.egovernment.moa.id.process;
+
+/**
+ * Indicates a problem when executing a process.
+ *
+ * @author tknall
+ *
+ */
+public class ProcessExecutionException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new process execution exception providing a {@code message} describing the reason and the respective
+ * {@code cause}.
+ *
+ * @param message
+ * The message.
+ * @param cause
+ * The cause.
+ */
+ public ProcessExecutionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new process execution exception providing a {@code message} describing the reason.
+ *
+ * @param message
+ * The message.
+ */
+ public ProcessExecutionException(String message) {
+ super(message);
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstance.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstance.java
new file mode 100644
index 000000000..0899426ca
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstance.java
@@ -0,0 +1,166 @@
+package at.gv.egovernment.moa.id.process;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.time.DurationFormatUtils;
+
+import com.datentechnik.process_engine.api.ExecutionContext;
+import com.datentechnik.process_engine.model.ProcessDefinition;
+import com.datentechnik.process_engine.support.SecureRandomHolder;
+
+/**
+ * Represents a process being executed. The process instance provides information about the process and its state.
+ *
+ * @author tknall
+ *
+ */
+public class ProcessInstance implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private static final int RND_ID_LENGTH = 22;
+
+ private ProcessDefinition processDefinition;
+ private String nextId;
+ private Date lru;
+ private ExecutionContext executionContext;
+ private ProcessInstanceState state = ProcessInstanceState.NOT_STARTED;
+
+ /**
+ * Creates a new process instance, based on a given process definition.
+ * An execution context will be created internally.
+ *
+ * @param processDefinition
+ * The process definition.
+ */
+ ProcessInstance(ProcessDefinition processDefinition) {
+ this(processDefinition, null);
+ }
+
+ /**
+ * Creates a new process instance, based on a given process definition and a
+ * given execution context. If the given execution context is {@code null} a new execution context will be created.
+ * The process instance id of the execution context will automatically be set (and overwritten if already set).
+ *
+ * @param processDefinition
+ * The process definition.
+ * @param executionContext
+ * The execution context (may be {@code null}). If {@code null} a new execution context will be created internally.
+ */
+ ProcessInstance(ProcessDefinition processDefinition, ExecutionContext executionContext) {
+ this.processDefinition = processDefinition;
+ nextId = processDefinition.getStartEvent().getId();
+ String pdIdLocalPart = RandomStringUtils.random(RND_ID_LENGTH, 0, 0, true, true, null,
+ SecureRandomHolder.getInstance());
+ if (executionContext == null) {
+ executionContext = new ExecutionContextImpl();
+ }
+ executionContext.setProcessInstanceId(this.processDefinition.getId() + "-" + pdIdLocalPart);
+ this.executionContext = executionContext;
+ touch();
+ }
+
+ /**
+ * Returns the underlying process definition.
+ *
+ * @return The underlying process definition.
+ */
+ ProcessDefinition getProcessDefinition() {
+ touch();
+ return processDefinition;
+ }
+
+ /**
+ * Returns the id of the process node to be executed next.
+ *
+ * @return The process node pointer indicating the process node to be executed next.
+ */
+ public String getNextId() {
+ touch();
+ return nextId;
+ }
+
+ /**
+ * Sets the internal pointer to the process node to be executed next.
+ *
+ * @param nextId
+ * The process node id to be executed next.
+ */
+ void setNextId(String nextId) {
+ touch();
+ this.nextId = nextId;
+ }
+
+ /**
+ * Returns the current state of the process instance.
+ *
+ * @return The current state.
+ */
+ public ProcessInstanceState getState() {
+ touch();
+ return state;
+ }
+
+ /**
+ * Sets the current state of the process instance.
+ *
+ * @param state
+ * The current state.
+ */
+ void setState(ProcessInstanceState state) {
+ touch();
+ this.state = state;
+ }
+
+ public String getId() {
+ touch();
+ return executionContext.getProcessInstanceId();
+ }
+
+ /**
+ * Updates the last recently used date of the process instance.
+ */
+ private void touch() {
+ lru = new Date();
+ }
+
+ /**
+ * Returns the date the process instance has been accessed last.
+ *
+ * @return The last recently used date.
+ */
+ Date getLru() {
+ return lru;
+ }
+
+ /**
+ * Returns the associated execution context.
+ * @return The execution context (never {@code null}).
+ */
+ public ExecutionContext getExecutionContext() {
+ touch();
+ return executionContext;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("ProcessInstance [");
+ builder.append("id=").append(executionContext.getProcessInstanceId());
+ builder.append(", idle since=").append(
+ DurationFormatUtils.formatDurationWords(new Date().getTime() - this.lru.getTime(), true, true));
+ if (processDefinition != null) {
+ builder.append(", processDefinition.id=");
+ builder.append(processDefinition.getId());
+ }
+ if (nextId != null) {
+ builder.append(", nextId=");
+ builder.append(nextId);
+ }
+ builder.append(", executionContext=").append(executionContext);
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstanceState.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstanceState.java
new file mode 100644
index 000000000..2765283a0
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessInstanceState.java
@@ -0,0 +1,30 @@
+package at.gv.egovernment.moa.id.process;
+
+/**
+ * Represents a certain process instance state.
+ * @author tknall
+ *
+ */
+public enum ProcessInstanceState {
+
+ /**
+ * Indicates that the process with this process instance has not yet been started.
+ */
+ NOT_STARTED,
+
+ /**
+ * Indicates that the process is currently running.
+ */
+ STARTED,
+
+ /**
+ * Indicates that the process has been suspended until being waken up by someonce calling {@code signal}.
+ */
+ SUSPENDED,
+
+ /**
+ * Indicates that the process has been completed.
+ */
+ ENDED
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExecutionContext.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExecutionContext.java
new file mode 100644
index 000000000..4a9dfc336
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExecutionContext.java
@@ -0,0 +1,63 @@
+package at.gv.egovernment.moa.id.process.api;
+
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * Encapsulates data needed for or provided by task execution.
+ *
+ * @author tknall
+ *
+ */
+public interface ExecutionContext extends Serializable {
+
+ /**
+ * Returns the identifier of underlying process instance.
+ *
+ * @return The identifier of the process instance.
+ */
+ String getProcessInstanceId();
+
+ /**
+ * Sets the identifier of underlying process instance.
+ *
+ * @param processInstanceId
+ * The identifier of the process instance.
+ */
+ void setProcessInstanceId(String processInstanceId);
+
+ /**
+ * Stores a serializable object using {@code key}.
+ *
+ * @param key
+ * The key under that the {@code object} should be stored.
+ * @param object The object to be stored.
+ */
+ void put(String key, Serializable object);
+
+ /**
+ * Returns an serializable object stored within this process context using {@code key}.
+ *
+ * @param key
+ * The key that has been used to store the serializable object (may be {@code null}).
+ * @return The object or {@code null} in case the key does not relate to a stored object or the stored object itself
+ * was {@code null}.
+ */
+ Serializable get(String key);
+
+ /**
+ * Removes the object stored using {@code key}.
+ * @param key
+ * The key that has been used to store the serializable object (may be {@code null}).
+ * @return The object that has been removed or {@code null} there was no object stored using {@code key}.
+ */
+ Serializable remove(String key);
+
+ /**
+ * Returns an unmodifiable set containing the stored keys.
+ *
+ * @return The keyset (never {@code null}).
+ */
+ Set keySet();
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluationContext.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluationContext.java
new file mode 100644
index 000000000..bb3b267cf
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluationContext.java
@@ -0,0 +1,23 @@
+package at.gv.egovernment.moa.id.process.api;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import com.datentechnik.process_engine.model.Transition;
+
+/**
+ * Context used for evaluation of condition expressions set for {@linkplain Transition Transitions}.
+ *
+ * @author tknall
+ *
+ */
+public interface ExpressionEvaluationContext extends Serializable {
+
+ /**
+ * Returns the context data map used for expression evaluation.
+ *
+ * @return An unmodifiable map (never {@code null}).
+ */
+ Map getCtx();
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluator.java
new file mode 100644
index 000000000..fe0743201
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/ExpressionEvaluator.java
@@ -0,0 +1,25 @@
+package at.gv.egovernment.moa.id.process.api;
+
+/**
+ * Evaluates a given {@code expression} returning a boolean value.
+ *
+ * @author tknall
+ */
+public interface ExpressionEvaluator {
+
+ /**
+ * Evaluates a given {@code expression} returning a boolean value.
+ *
+ * @param expressionContext
+ * The context which can be used for evaluation of the expression.
+ * @param expression
+ * The expression resulting in a boolean (must not be {@code null}).
+ * @return A boolean value.
+ * @throws IllegalArgumentException
+ * In case of an invalid {@code expression}.
+ * @throws NullPointerException
+ * In case of a {@code null} expression.
+ */
+ boolean evaluate(ExpressionEvaluationContext expressionContext, String expression);
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/Task.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/Task.java
new file mode 100644
index 000000000..6401b1d5d
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/api/Task.java
@@ -0,0 +1,21 @@
+package at.gv.egovernment.moa.id.process.api;
+
+
+/**
+ * Represents a single task to be performed upon process execution.
+ *
+ * @author tknall
+ *
+ */
+public interface Task {
+
+ /**
+ * Executes this task.
+ *
+ * @param executionContext
+ * Provides execution related information.
+ * @throws Exception An exception upon task execution.
+ */
+ void execute(ExecutionContext executionContext) throws Exception;
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/EndEvent.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/EndEvent.java
new file mode 100644
index 000000000..49fb082ea
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/EndEvent.java
@@ -0,0 +1,42 @@
+package at.gv.egovernment.moa.id.process.model;
+
+import java.io.Serializable;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+/**
+ * Represents an end event. Process execution terminates when an end event is reached.
+ *
+ * @author tknall
+ */
+public class EndEvent extends ProcessNode implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("EndEvent [");
+ if (getId() != null) {
+ builder.append("id=");
+ builder.append(getId());
+ }
+ if (CollectionUtils.isNotEmpty(getIncomingTransitions())) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("incomingTransitions=");
+ builder.append(getIncomingTransitions());
+ }
+ if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("outgoingTransitions=");
+ builder.append(getOutgoingTransitions());
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessDefinition.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessDefinition.java
new file mode 100644
index 000000000..19e78b0e6
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessDefinition.java
@@ -0,0 +1,158 @@
+package at.gv.egovernment.moa.id.process.model;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import com.datentechnik.process_engine.ProcessDefinitionParser;
+
+/**
+ * Represents a single process definition containing
+ *
+ * - a {@link StartEvent},
+ * - one or more {@linkplain TaskInfo Tasks},
+ * - one or more {@linkplain EndEvent EndEvents} and
+ * - some {@linkplain Transition Transitions} linking StartEvents, Tasks and EndEvents.
+ *
+ *
+ * @author tknall
+ *
+ */
+public class ProcessDefinition {
+
+ private String id;
+ private StartEvent startEvent;
+ private Map taskInfos = new LinkedHashMap<>();
+ private Map endEvents = new LinkedHashMap<>();
+
+ /**
+ * Returns the unique identifier of the process definition.
+ *
+ * @return The unique identifier (never {@code null} if process definition comes from
+ * {@link ProcessDefinitionParser}).
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the unique identifier of the process definition.
+ *
+ * @param id
+ * The unique identifier.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Returns the start event of the process definition.
+ *
+ * @return The start event (never {@code null} if process definition comes from {@link ProcessDefinitionParser}).
+ */
+ public StartEvent getStartEvent() {
+ return startEvent;
+ }
+
+ /**
+ * Sets the start event of the process definition.
+ *
+ * @param startEvent
+ * The start event.
+ */
+ public void setStartEvent(StartEvent startEvent) {
+ this.startEvent = startEvent;
+ }
+
+ /**
+ * Returns a map containing the tasks of the process definition.
+ *
+ * @return The tasks (map is never {@code null} if process definition comes from {@link ProcessDefinitionParser}).
+ */
+ public Map getTaskInfos() {
+ return taskInfos;
+ }
+
+ /**
+ * Sets the map containing the tasks.
+ *
+ * @param taskInfos
+ * The map containing the tasks.
+ */
+ public void setTaskInfos(Map taskInfos) {
+ this.taskInfos = taskInfos;
+ }
+
+ /**
+ * Returns a map containing the end events of the process description.
+ *
+ * @return The map containing the end events (map is never {@code null} if process definition comes from
+ * {@link ProcessDefinitionParser}).
+ */
+ public Map getEndEvents() {
+ return endEvents;
+ }
+
+ /**
+ * Sets a map containing the end events of the process description.
+ *
+ * @param endEvents
+ * The map containing the end events.
+ */
+ public void setEndEvents(Map endEvents) {
+ this.endEvents = endEvents;
+ }
+
+ /**
+ * Returns the process node associated with the given {@code id}.
+ *
+ * @param id
+ * The identifier of the process node.
+ * @return The process node (may be {code null} when no process node with the given {@code id} exists).
+ */
+ public ProcessNode getProcessNode(String id) {
+ Objects.requireNonNull(id, "Identifier must not be null.");
+ if (startEvent != null && id.equals(startEvent.getId())) {
+ return startEvent;
+ }
+ TaskInfo task = taskInfos.get(id);
+ if (task != null) {
+ return task;
+ }
+ return endEvents.get(id);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (id != null) {
+ builder.append("id=");
+ builder.append(id);
+ }
+ if (startEvent != null) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("startEvent=");
+ builder.append(startEvent);
+ }
+ if (taskInfos != null && !taskInfos.isEmpty()) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("tasksInfos=");
+ builder.append(taskInfos.values());
+ }
+ if (endEvents != null && !endEvents.isEmpty()) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("endEvents=");
+ builder.append(endEvents.values());
+ }
+ builder.insert(0, "ProcessDefinition [");
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessNode.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessNode.java
new file mode 100644
index 000000000..a94d33943
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/ProcessNode.java
@@ -0,0 +1,69 @@
+package at.gv.egovernment.moa.id.process.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.datentechnik.process_engine.ProcessDefinitionParser;
+
+/**
+ * Represents a {@link StartEvent}, an {@link EndEvent} or a {@linkplain TaskInfo Task}.
+ * @author tknall
+ *
+ */
+public abstract class ProcessNode {
+
+ private String id;
+ private List outgoingTransitions = new ArrayList<>();
+ private List incomingTransitions = new ArrayList<>();
+
+ /**
+ * Returns the unique identifier of the process node.
+ *
+ * @return The unique identifier (never {@code null} if process node comes from a process definition from
+ * {@link ProcessDefinitionParser}).
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the unique identifier of the process node.
+ * @param id The unique identifier.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Returns a list of transitions pointing from this process node to another one.
+ * @return A list of transitions (never {@code null} if process node comes from a process definition from {@link ProcessDefinitionParser}).
+ */
+ public List getOutgoingTransitions() {
+ return outgoingTransitions;
+ }
+
+ /**
+ * Sets the list of transitions pointing from this process node to another one.
+ * @param outgoingTransitions The list of transitions originating from this process node.
+ */
+ public void setOutgoingTransitions(List outgoingTransitions) {
+ this.outgoingTransitions = outgoingTransitions;
+ }
+
+ /**
+ * Returns a list of transitions pointing from another process node to this one.
+ * @return A list of transitions (never {@code null} if process node comes from a process definition from {@link ProcessDefinitionParser}).
+ */
+ public List getIncomingTransitions() {
+ return incomingTransitions;
+ }
+
+ /**
+ * Sets the list of transitions pointing from another process node to this one.
+ * @param incomingTransitions A list of transitions pointing to this process node.
+ */
+ public void setIncomingTransitions(List incomingTransitions) {
+ this.incomingTransitions = incomingTransitions;
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/StartEvent.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/StartEvent.java
new file mode 100644
index 000000000..60175e09c
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/StartEvent.java
@@ -0,0 +1,45 @@
+package at.gv.egovernment.moa.id.process.model;
+
+import java.io.Serializable;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+/**
+ * Represents a start event. Each process description contains a single start event. Process execution starts with a
+ * start event.
+ *
+ * @author tknall
+ *
+ */
+public class StartEvent extends ProcessNode implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("StartEvent [");
+ if (getId() != null) {
+ builder.append("id=");
+ builder.append(getId());
+ }
+ if (CollectionUtils.isNotEmpty(getIncomingTransitions())) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("incomingTransitions=");
+ builder.append(getIncomingTransitions());
+ }
+ if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("outgoingTransitions=");
+
+ builder.append(getOutgoingTransitions());
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/TaskInfo.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/TaskInfo.java
new file mode 100644
index 000000000..b7f13a880
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/TaskInfo.java
@@ -0,0 +1,94 @@
+package at.gv.egovernment.moa.id.process.model;
+
+import java.io.Serializable;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+import com.datentechnik.process_engine.api.Task;
+
+/**
+ * Represents information about a single task to be performed upon process execution.
+ * @author tknall
+ *
+ */
+public class TaskInfo extends ProcessNode implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private static final boolean DEFAULT_ASYNC = false;
+
+ private String taskImplementingClass;
+ private boolean async = DEFAULT_ASYNC;
+
+ /**
+ * Determines if the task is marked asynchronous ({@code true}) or synchronous ({@code false}).
+ * @return A flag indicating if the task should be executed asynchronously or synchronously. (Default: {@code false})
+ */
+ public boolean isAsync() {
+ return async;
+ }
+
+ /**
+ * Marks a task to executed asynchronously ({@code true}) or synchronously ({@code false}).
+ * @param async The flag.
+ */
+ public void setAsync(boolean async) {
+ this.async = async;
+ }
+
+ /**
+ * Returns the class that implements the actual task (must implement {@link Task}).
+ * @return The task implementing class.
+ */
+ public String getTaskImplementingClass() {
+ return taskImplementingClass;
+ }
+
+ /**
+ * Sets the class that implements the actual task (must implement {@link Task}).
+ * @param taskImplementingClass The task implementing class.
+ */
+ public void setTaskImplementingClass(String taskImplementingClass) {
+ this.taskImplementingClass = taskImplementingClass;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (getId() != null) {
+ builder.append("id=");
+ builder.append(getId());
+ }
+ if (async != DEFAULT_ASYNC) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("async=");
+ builder.append(async);
+ }
+ if (taskImplementingClass != null) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("taskImplementingClass=");
+ builder.append(taskImplementingClass);
+ }
+ if (CollectionUtils.isNotEmpty(getIncomingTransitions())) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("incomingTransitions=");
+ builder.append(getIncomingTransitions());
+ }
+ if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("outgoingTransitions=");
+ builder.append(getOutgoingTransitions());
+ }
+ builder.insert(0, "TaskInfo [");
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/Transition.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/Transition.java
new file mode 100644
index 000000000..9d9c44c8c
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/model/Transition.java
@@ -0,0 +1,136 @@
+package at.gv.egovernment.moa.id.process.model;
+
+import java.io.Serializable;
+
+import com.datentechnik.process_engine.ProcessDefinitionParser;
+
+/**
+ * Represents a single transition from a {@link StartEvent} or {@linkplain TaskInfo Task} to another
+ * {@linkplain TaskInfo Task} or {@link EndEvent}.
+ *
+ * @author tknall
+ *
+ */
+public class Transition implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private String id;
+ private String conditionExpression;
+ private ProcessNode from;
+ private ProcessNode to;
+
+ /**
+ * Returns the process node (effectively a {@link StartEvent} or {@linkplain TaskInfo Task}) the transition is
+ * pointing from.
+ *
+ * @return The transition's source process node (never {@code null} if transition comes from a process definition
+ * from {@link ProcessDefinitionParser}).
+ */
+ public ProcessNode getFrom() {
+ return from;
+ }
+
+ /**
+ * Sets the process node the transition is pointing from.
+ *
+ * @param from
+ * The transition's source process node.
+ */
+ public void setFrom(ProcessNode from) {
+ this.from = from;
+ }
+
+ /**
+ * Returns the process node (effectively a {@linkplain TaskInfo Task} or {@link EndEvent}) the transition is
+ * pointing to.
+ *
+ * @return The transition's destination process node (never {@code null} if transition comes from a process
+ * definition from {@link ProcessDefinitionParser}).
+ */
+ public ProcessNode getTo() {
+ return to;
+ }
+
+ /**
+ * Sets the process node the transition is pointing to.
+ *
+ * @param to
+ * The transition's destination process node.
+ */
+ public void setTo(ProcessNode to) {
+ this.to = to;
+ }
+
+ /**
+ * Returns the unique identifier of the transition.
+ *
+ * @return The unique identifier (may be {@code null}).
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the unique identifier of the transition.
+ *
+ * @param id
+ * The unique identifier.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Returns the condition expression for this transition.
+ *
+ * @return The condition expression (may be {@code null}).
+ */
+ public String getConditionExpression() {
+ return conditionExpression;
+ }
+
+ /**
+ * Sets the condition expression for this transition.
+ *
+ * @param conditionExpression
+ * The condition expression.
+ */
+ public void setConditionExpression(String conditionExpression) {
+ this.conditionExpression = conditionExpression;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (id != null) {
+ builder.append("id=");
+ builder.append(id);
+ }
+ if (from != null) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("from.id=");
+ builder.append(from.getId());
+ }
+ if (to != null) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("to.id=");
+ builder.append(to.getId());
+ }
+ if (conditionExpression != null) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append("conditionExpression=");
+ builder.append(conditionExpression);
+ }
+ builder.insert(0, "Transition [");
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/spring/SpringExpressionEvaluator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/spring/SpringExpressionEvaluator.java
new file mode 100644
index 000000000..1c91cf780
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/spring/SpringExpressionEvaluator.java
@@ -0,0 +1,61 @@
+package at.gv.egovernment.moa.id.process.spring;
+
+import java.util.Objects;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.lang3.BooleanUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.expression.BeanFactoryResolver;
+import org.springframework.expression.Expression;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+
+import com.datentechnik.process_engine.api.ExpressionEvaluationContext;
+import com.datentechnik.process_engine.api.ExpressionEvaluator;
+import com.datentechnik.process_engine.model.Transition;
+
+/**
+ * Expression evaluator for processing {@link Transition} conditions allowing to reference Spring beans from the
+ * application context.
+ *
+ * @author tknall
+ *
+ */
+public class SpringExpressionEvaluator implements ExpressionEvaluator {
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+ private ExpressionParser parser = new SpelExpressionParser();
+ private StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
+
+ @Autowired(required = false)
+ private ApplicationContext ctx;
+
+ @PostConstruct
+ private void init() {
+ if (ctx != null) {
+ evaluationContext.setBeanResolver(new BeanFactoryResolver(ctx));
+ }
+ }
+
+ @Override
+ public boolean evaluate(ExpressionEvaluationContext expressionContext, String expression) {
+ Objects.requireNonNull(expression, "Expression must not be null.");
+ log.trace("Evaluating '{}'.", expression);
+
+ Expression expr = parser.parseExpression(expression);
+ Boolean result = expr.getValue(evaluationContext, expressionContext, Boolean.class);
+ if (result == null) {
+ log.warn("Evaluation of '{}' results in null-value.", expression);
+ } else {
+ log.debug("Expression '{}' -> {}", expression, result);
+ }
+
+ return BooleanUtils.isTrue(result);
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractAuthSourceServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractAuthSourceServlet.java
new file mode 100644
index 000000000..4b5af854e
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractAuthSourceServlet.java
@@ -0,0 +1,116 @@
+package at.gv.egovernment.moa.id.process.springweb;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+import com.datentechnik.process_engine.ProcessEngine;
+import com.datentechnik.process_engine.ProcessInstance;
+import com.datentechnik.process_engine.api.ExecutionContext;
+
+/**
+ * Abstract HttpServlet that provides means for retrieving the process engine (Spring Web required) as well as
+ * retrieving the underlying process instance and execution context evaluating a certain request parameter.
+ *
+ * @author tknall
+ *
+ */
+public abstract class AbstractAuthSourceServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private ProcessEngine processEngine;
+
+ /**
+ * Returns the name of the request parameter representing the respective instance id.
+ * Default is {@code processInstanceId}.
+ * @return The request parameter name.
+ */
+ public String getProcessInstanceIdParameterName() {
+ return "processInstanceId";
+ }
+
+ /**
+ * Returns the underlying process engine instance.
+ *
+ * @return The process engine (never {@code null}).
+ * @throws NoSuchBeanDefinitionException
+ * if no {@link ProcessEngine} bean was found.
+ * @throws NoUniqueBeanDefinitionException
+ * if more than one {@link ProcessEngine} bean was found.
+ * @throws BeansException
+ * if a problem getting the {@link ProcessEngine} bean occurred.
+ * @throws IllegalStateException
+ * if the Spring WebApplicationContext was not found, which means that the servlet is used outside a
+ * Spring web environment.
+ */
+ public synchronized ProcessEngine getProcessEngine() {
+ if (processEngine == null) {
+ WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
+ if (ctx == null) {
+ throw new IllegalStateException(
+ "Unable to find Spring WebApplicationContext. Servlet needs to be executed within a Spring web environment.");
+ }
+ processEngine = ctx.getBean(ProcessEngine.class);
+ }
+ return processEngine;
+ }
+
+ /**
+ * Retrieves the process instance referenced by the request parameter {@link #getProcessInstanceIdParameterName()}.
+ *
+ * @param request
+ * The HttpServletRequest.
+ * @return The process instance (never {@code null}).
+ * @throws NoSuchBeanDefinitionException
+ * if no {@link ProcessEngine} bean was found.
+ * @throws NoUniqueBeanDefinitionException
+ * if more than one {@link ProcessEngine} bean was found.
+ * @throws BeansException
+ * if a problem getting the {@link ProcessEngine} bean occurred.
+ * @throws IllegalStateException
+ * if the Spring WebApplicationContext was not found, which means that the servlet is used outside a
+ * Spring web environment.
+ * @throws IllegalArgumentException
+ * in case the process instance id referenced by the request parameter
+ * {@link #getProcessInstanceIdParameterName()} does not exist.
+ */
+ public ProcessInstance getProcessInstance(HttpServletRequest request) {
+ String processInstanceId = StringUtils.trimToNull(request.getParameter(getProcessInstanceIdParameterName()));
+ if (processInstanceId == null) {
+ throw new IllegalArgumentException("Missing request parameter '" + getProcessInstanceIdParameterName() + "'.");
+ }
+ return getProcessEngine().getProcessInstance(processInstanceId);
+ }
+
+ /**
+ * Retrieves the execution context for the respective process instance referenced by the request parameter
+ * {@link #getProcessInstanceIdParameterName()}.
+ *
+ * @param request
+ * The HttpServletRequest.
+ * @return The execution context (never {@code null}).
+ * @throws NoSuchBeanDefinitionException
+ * if no {@link ProcessEngine} bean was found.
+ * @throws NoUniqueBeanDefinitionException
+ * if more than one {@link ProcessEngine} bean was found.
+ * @throws BeansException
+ * if a problem getting the {@link ProcessEngine} bean occurred.
+ * @throws IllegalStateException
+ * if the Spring WebApplicationContext was not found, which means that the servlet is used outside a
+ * Spring web environment.
+ * @throws IllegalArgumentException
+ * in case the process instance id referenced by the request parameter
+ * {@link #getProcessInstanceIdParameterName()} does not exist.
+ */
+ public ExecutionContext getExecutionContext(HttpServletRequest request) {
+ return getProcessInstance(request).getExecutionContext();
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractSpringWebSupportedTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractSpringWebSupportedTask.java
new file mode 100644
index 000000000..1f7fb7690
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/springweb/AbstractSpringWebSupportedTask.java
@@ -0,0 +1,73 @@
+package at.gv.egovernment.moa.id.process.springweb;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.filter.RequestContextFilter;
+
+import com.datentechnik.process_engine.api.ExecutionContext;
+import com.datentechnik.process_engine.api.Task;
+
+/**
+ * Abstract task implementation providing {@link HttpServletRequest} and {@link HttpServletResponse}.
+ *
+ * Note that this abstract task requires the Spring (web) framework including a {@link RequestContextFilter} to be set
+ * within {@code web.xml}.
+ *
+ *
+ * ...
+ * <filter>
+ * <filter-name>requestContextFilter</filter-name>
+ * <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
+ * </filter>
+ * <filter-mapping>
+ * <filter-name>requestContextFilter</filter-name>
+ * <url-pattern>/*</url-pattern>
+ * </filter-mapping>
+ * ...
+ *
+ *
+ * @author tknall
+ *
+ */
+public abstract class AbstractSpringWebSupportedTask implements Task {
+
+ /**
+ * Executes the task providing the underlying {@link ExecutionContext} {@code executionContext} as well as the
+ * respective {@link HttpServletRequest} and {@link HttpServletResponse}.
+ *
+ * @param executionContext
+ * The execution context (never {@code null}).
+ * @param request
+ * The HttpServletRequest (never {@code null}).
+ * @param response
+ * The HttpServletResponse (never {@code null}).
+ * @throws IllegalStateException
+ * Thrown in case the task is nur being run within the required environment. Refer to javadoc for
+ * further information.
+ * @throws Exception
+ * Thrown in case of error executing the task.
+ */
+ public abstract void execute(ExecutionContext executionContext, HttpServletRequest request,
+ HttpServletResponse response) throws Exception;
+
+ @Override
+ public void execute(ExecutionContext executionContext) throws Exception {
+ RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
+ if (requestAttributes != null && requestAttributes instanceof ServletRequestAttributes) {
+ HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
+ HttpServletResponse response = ((ServletRequestAttributes) requestAttributes).getResponse();
+ if (request == null || response == null) {
+ throw new IllegalStateException(
+ "Spring's RequestContextHolder did not provide HttpServletResponse. Did you forget to set the required org.springframework.web.filter.RequestContextFilter in your web.xml.");
+ }
+ execute(executionContext, request, response);
+ } else {
+ throw new IllegalStateException("Task needs to be executed within a Spring web environment.");
+ }
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/support/SecureRandomHolder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/support/SecureRandomHolder.java
new file mode 100644
index 000000000..72677739a
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/support/SecureRandomHolder.java
@@ -0,0 +1,35 @@
+package at.gv.egovernment.moa.id.process.support;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+/**
+ * Holder for a secure random instance following the initialization on demand holder design pattern. The secure random
+ * instance is a singleton that is initialized on first usage.
+ *
+ * @author tknall
+ *
+ */
+public class SecureRandomHolder {
+
+ private SecureRandomHolder() {
+ }
+
+ private static final SecureRandom SRND_INSTANCE;
+ static {
+ try {
+ SRND_INSTANCE = SecureRandom.getInstance("SHA1PRNG");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("Unable to instantiate SHA1PRNG.", e);
+ }
+ }
+
+ /**
+ * Returns a secure random generator instance.
+ * @return The secure random instance.
+ */
+ public static SecureRandom getInstance() {
+ return SecureRandomHolder.SRND_INSTANCE;
+ }
+
+}
\ No newline at end of file
diff --git a/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModule b/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModule
new file mode 100644
index 000000000..22f39a923
--- /dev/null
+++ b/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModule
@@ -0,0 +1,2 @@
+# The default moaid process
+at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModuleImpl
\ No newline at end of file
diff --git a/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.modulregistration.AuthModule b/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.modulregistration.AuthModule
deleted file mode 100644
index 0d7e98006..000000000
--- a/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.modulregistration.AuthModule
+++ /dev/null
@@ -1,2 +0,0 @@
-# The default moaid process
-at.gv.egovernment.moa.id.moduls.modulregistration.AuthModuleImpl
\ No newline at end of file
diff --git a/id/server/idserverlib/src/main/resources/at/gv/egovernment/moa/id/process/ProcessDefinition.xsd b/id/server/idserverlib/src/main/resources/at/gv/egovernment/moa/id/process/ProcessDefinition.xsd
new file mode 100644
index 000000000..42db4f807
--- /dev/null
+++ b/id/server/idserverlib/src/main/resources/at/gv/egovernment/moa/id/process/ProcessDefinition.xsd
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SampleProcessDefinitionForSAML1Authentication.xml b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SampleProcessDefinitionForSAML1Authentication.xml
new file mode 100644
index 000000000..6525fb0cd
--- /dev/null
+++ b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SampleProcessDefinitionForSAML1Authentication.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SampleProcessDefinitionWithExpression1.xml b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SampleProcessDefinitionWithExpression1.xml
new file mode 100644
index 000000000..ef71026ec
--- /dev/null
+++ b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SampleProcessDefinitionWithExpression1.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SpringExpressionAwareProcessEngineTest-context.xml b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SpringExpressionAwareProcessEngineTest-context.xml
new file mode 100644
index 000000000..eb62d1ae2
--- /dev/null
+++ b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SpringExpressionAwareProcessEngineTest-context.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SpringExpressionEvaluatorTest-context.xml b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SpringExpressionEvaluatorTest-context.xml
new file mode 100644
index 000000000..dadc6bf81
--- /dev/null
+++ b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/SpringExpressionEvaluatorTest-context.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/task/IdentityLink_Max_Mustermann.xml b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/task/IdentityLink_Max_Mustermann.xml
new file mode 100644
index 000000000..c68972f13
--- /dev/null
+++ b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/task/IdentityLink_Max_Mustermann.xml
@@ -0,0 +1,52 @@
+
+
+
+
+ urn:oasis:names:tc:SAML:1.0:cm:sender-vouches
+
+ tqCQEC7+AqGEeeL390V5Jg==urn:publicid:gv.at:baseidMaxMustermann1940-01-01
+
+
+
+
+
+
+
+
+
+
+
+ not(ancestor-or-self::pr:Identification)
+
+
+
+
+ Rmr5vkWXL/PvpoXnbK632QmzYms=
+
+
+
+ HoPZWYll8aMFpKOlRSwckt5iCQk=
+
+
+
+ NPpRwVo5/5kf5iHUyaEc7d7So3W4oPgOCYNgnKpgdZfttFkFFN+9oG60w7YvKEYSeTPhP3zp7eaH
+ZFapj+naD+wd0y5ELWep9Y+s+qP7fNLrFECHQxQasLWtR4akxlWDpYQ0bvOuepK2ip1EQ6pRlccA
+wJ1l4iOWFhfdA9YAg5QLkBqWSwgrNUswhLnDBM+Ot6Gj5g2rpYY7aoAOXvTR8B5Dkg94ASb4u0wv
+VPV8+4mjOfP+l6QWLqywzcq3qj/qFZkbujjZbV/fNPDnDD1ff/M6ZfCGO8xzlYfjfEA7cmHuiJf2
+/ey/3nT7vI5XbpBPWChT5Sl4DQysxlfE6e4MZw==
+ MIIF3TCCBMWgAwIBAgIDByniMA0GCSqGSIb3DQEBBQUAMIGfMQswCQYDVQQGEwJBVDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMSIwIAYDVQQLDBlhLXNpZ24tY29ycG9yYXRlLWxpZ2h0LTAyMSIwIAYDVQQDDBlhLXNpZ24tY29ycG9yYXRlLWxpZ2h0LTAyMB4XDTEwMDcyODExMzY0M1oXDTE1MDcyODExMzY0M1owgbYxCzAJBgNVBAYTAkFUMR4wHAYDVQQKDBVEYXRlbnNjaHV0emtvbW1pc3Npb24xIjAgBgNVBAsMGVN0YW1temFobHJlZ2lzdGVyYmVob2VyZGUxLjAsBgNVBAMMJVNpZ25hdHVyc2VydmljZSBEYXRlbnNjaHV0emtvbW1pc3Npb24xFTATBgNVBAUTDDMyNTkyODMyMzk5ODEcMBoGCSqGSIb3DQEJARYNZHNrQGRzay5ndi5hdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN+dBSEBGj2jUXIK1Mp3lVxc/Za+pJMiyKrX3G1ZxgX/ikx7D9scsPYMt473LlAWl9cmCbHbJK+PV2XNNdURLMUCIX+4vUNs2MHeDTQtX8BXjJFpwJYSoaRJQ39FVS/1r5sWcra9Hhdm7w5Gtx/2ukyDX0kdkxawkhP4EQEzi/SI+Fugn+WqgQ1nAdlbxb/dcBw5w1h9b3lmuwUf4z3ooQWUD2DgA/kKd1KejNR43mLUsmvSzevPxT9zs78pOR1OacB7IszTVJPXeOEaaNZHnnB/UeO3g8LEV/3OkXcUgcMkbIIiaBHlll71Pq0COj9kqjXoe7OrRjLY5i3KwOpa6TMCAwEAAaOCAgcwggIDMBMGA1UdIwQMMAqACEkcWDpP6A0DMH8GCCsGAQUFBwEBBHMwcTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AuYS10cnVzdC5hdC9vY3NwMEYGCCsGAQUFBzAChjpodHRwOi8vd3d3LmEtdHJ1c3QuYXQvY2VydHMvYS1zaWduLWNvcnBvcmF0ZS1saWdodC0wMmEuY3J0MFQGA1UdIARNMEswSQYGKigAEQESMD8wPQYIKwYBBQUHAgEWMWh0dHA6Ly93d3cuYS10cnVzdC5hdC9kb2NzL2NwL2Etc2lnbi1BbXRzc2lnbmF0dXIwgZ4GA1UdHwSBljCBkzCBkKCBjaCBioaBh2xkYXA6Ly9sZGFwLmEtdHJ1c3QuYXQvb3U9YS1zaWduLWNvcnBvcmF0ZS1saWdodC0wMixvPUEtVHJ1c3QsYz1BVD9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0P2Jhc2U/b2JqZWN0Y2xhc3M9ZWlkQ2VydGlmaWNhdGlvbkF1dGhvcml0eTARBgNVHQ4ECgQITAgOnhr0tbowDgYDVR0PAQH/BAQDAgSwMCAGA1UdEQQZMBeBFW1hcmN1cy5oaWxkQGRzay5ndi5hdDAJBgNVHRMEAjAAMA4GByooAAoBBwEEAwEB/zAUBgcqKAAKAQEBBAkMB0JTQi1EU0swDQYJKoZIhvcNAQEFBQADggEBAHTklnvPCH/bJSOlIPbLUEkSGuFHsektSZ8Vr22x/Yv7EzsxoQrJIiz2mQ2gQqFuExdWYxvsowjiSbiis9iUf1c0zscvDS3mIZxGs4M89XHsjHnIyb+Fuwnamw65QrFvM1tNB1ZMjxJ3x+YmHLHdtT3BEBcr3/NCRHd2S0HoBspNz9HVgJaZY1llR7poKBvnAc4g1i+QTvyVb00PtKxR9Lw/9ABInX/1pzpxqrPy7Ib2OP8z6dd3WHmIsCiSHUaj0Dxwwln6fYJjhxZ141SnbovlCLYtrsZLXoi9ljIqX4xO0PwMI2RfNc9cXxTRrRS6rEOvX7PpvgXiDXhp592Yyp4=
+
+
+
+
+
+ not(ancestor-or-self::dsig:Signature)
+
+
+
+ 7IkIdYti2dh3VZQ4Fp+9lPT67cM=
+
+
+
+
+
\ No newline at end of file
diff --git a/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/task/SAML1Assertion.xml b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/task/SAML1Assertion.xml
new file mode 100644
index 000000000..3aeedd590
--- /dev/null
+++ b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/task/SAML1Assertion.xml
@@ -0,0 +1,487 @@
+
+
+
+
+ K2YMyx3/5kIpNJR+SAD/rbRYH+c=
+
+ http://reference.e-government.gv.at/namespace/moa/20020822#cm
+
+
+
+
+ https://localhost:18443/moa-id-auth/
+
+
+
+
+ K2YMyx3/5kIpNJR+SAD/rbRYH+c=
+ urn:publicid:gv.at:wbpk+FN+www.act.at
+
+
+
+
+ https://localhost:48443/mandates/
+
+
+ 1978-04-29
+
+
+ Vollmachtsvertreter
+
+
+ MeineTestFirma
+
+
+ 123456i
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Signatur der Anmeldedaten
+
+
+
+ Signatur der Anmeldedaten
+
+ Mit meiner elektronischen Signatur beantrage ich,
+
+
+ , geboren am
+ .
+ .
+ ,
+
+ in der Rolle als
+ (OID***= ),
+
+ den Zugang zur gesicherten Anwendung.
+
+
+ Datum und Uhrzeit:
+ .
+ .
+ ,
+ :
+ :
+
+
+
+ HPI(**):
+
+
+
+ wbPK(*):
+
+
+
+
+ Ich bin weiters ermächtigt als
+ von
+ , geboren am
+ .
+ .
+
+
+ ,
+
+ , in deren Auftrag zu handeln.
+
+
+ wbPK(*) des Vollmachtgebers:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (*) wbPK: Das wirtschaftsbereichsspezifische Personenkennzeichen wird aus den
+ jeweiligen Stammzahlen des Bürgers und des Wirtschaftsunternehmens berechnet und ermöglicht eine eindeutige Zuordnung des Bürgers zum
+ Wirtschaftsunternehmen.
+
+
+ (**) HPI: Der eHealth Professional Identifier wird aus den jeweiligen
+ Stammzahlen der Gesundheitsdiensteanbieterinnen / Gesundheitsdiensteanbieter berechnet und ermöglicht eine eindeutige Zuordnung der
+ Gesundheitsdiensteanbieterin / des Gesundheitsdiensteanbieters im Gesundheitsbereich.
+
+
+ (***) OID: Object Identifier sind standardisierte Objekt-Bezeichner und
+ beschreiben eindeutig die Rollen des GDA-Token Inhabers.
+
+
+
+
+
+
+
+
+
+ 0q9QWyqAyyiVNNLu1rIcU+nKsEE=
+
+
+
+ WtB0/ptvoB/r/7+fauSUIBULymg=
+
+
+ mZt9DuZiDqG81scsf30qjSDdy6vKC2/n034ZZwMUAvfWOXy3+Ubsk5X5CHhz
++lyI
+
+
+ MIIEtDCCA5ygAwIBAgIDAgTEMA0GCSqGSIb3DQEBBQUAMIGXMQswCQYDVQQG
+EwJBVDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lz
+dGVtZSBpbSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMR4wHAYDVQQLDBVh
+LXNpZ24tUHJlbWl1bS1TaWctMDIxHjAcBgNVBAMMFWEtc2lnbi1QcmVtaXVt
+LVNpZy0wMjAeFw0wNjA0MDQwOTUyMjhaFw0xMTA0MDQwOTUyMjhaMGkxCzAJ
+BgNVBAYTAkFUMRUwEwYDVQQDDAxUaG9tYXMgS25hbGwxDjAMBgNVBAQMBUtu
+YWxsMQ8wDQYDVQQqDAZUaG9tYXMxFTATBgNVBAUTDDUzNTE5ODkyMzM0OTEL
+MAkGA1UEDAwCREkwSTATBgcqhkjOPQIBBggqhkjOPQMBAQMyAARrnYW5sXCQ
+6M3irWaanDPi/ROXueKWiPRyZGjNH0Cp/NaiOuvrpv2RDVEKQm2tBiajggIP
+MIICCzATBgNVHSMEDDAKgAhN3+H/S9nJ3zAnBggrBgEFBQcBAwEB/wQYMBYw
+CAYGBACORgEBMAoGCCsGAQUFBwsBMHsGCCsGAQUFBwEBBG8wbTBCBggrBgEF
+BQcwAoY2aHR0cDovL3d3dy5hLXRydXN0LmF0L2NlcnRzL2Etc2lnbi1QcmVt
+aXVtLVNpZy0wMmEuY3J0MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5hLXRy
+dXN0LmF0L29jc3AwWQYDVR0gBFIwUDBEBgYqKAARAQswOjA4BggrBgEFBQcC
+ARYsaHR0cDovL3d3dy5hLXRydXN0LmF0L2RvY3MvY3AvYS1zaWduLVByZW1p
+dW0wCAYGBACLMAEBMIGaBgNVHR8EgZIwgY8wgYyggYmggYaGgYNsZGFwOi8v
+bGRhcC5hLXRydXN0LmF0L291PWEtc2lnbi1QcmVtaXVtLVNpZy0wMixvPUEt
+VHJ1c3QsYz1BVD9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0P2Jhc2U/b2Jq
+ZWN0Y2xhc3M9ZWlkQ2VydGlmaWNhdGlvbkF1dGhvcml0eTARBgNVHQ4ECgQI
+SNyH29WUoCgwDgYDVR0PAQH/BAQDAgbAMCgGA1UdCQQhMB8wHQYIKwYBBQUH
+CQExERgPMTk3ODA0MjkwMDAwMDBaMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEF
+BQADggEBAFkSCJE0YD4p4izU3ekQYPv4Z7gm/VFlpma5hXNvwkajVjHlAqo/
+ylYn8NQ4mMkD+yCDNtm8m8nr0K/yICb8Gnkbv59i6nh2AbzYBBb49VnYYGL6
+uunLH0aFUpAhy+3mDdlH8uhhIQBHwCfgwG1qa5zXY7bz4Vzkac/h6T+JVFkI
+egO8OHQDadhgJvW80qspiao2DTac6vVgx4tGvjpdmw1R2pXBYhHD5rkPHlkf
+GoeL3ak6hq4ea94Oy5VfNTIJv5MA0J2G1mwnW9B8uPWSM5EYPoWJyBOWcKBL
+SSUqOt9D/9215ZGfbchkdRZjx0dTAD3FIhgG8nA72/uCFrBzyTk=
+
+
+
+
+
+
+
+ 2008-07-14T15:51:35Z
+
+
+
+
+ inMYWBmAxMHP7mDENjLFaEtv0Zk=
+
+
+ CN=a-sign-Premium-Sig-02,OU=a-sign-Premium-Sig-02,O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH,C=AT
+ 132292
+
+
+
+
+
+
+
+
+
+ application/xhtml+xml
+
+
+
+
+
+
+
+
+
+
+
+ urn:oasis:names:tc:SAML:1.0:cm:sender-vouches
+
+
+
+ K2YMyx3/5kIpNJR+SAD/rbRYH+c=
+ urn:publicid:gv.at:wbpk+FN+www.act.at
+
+
+ Thomas
+ Knall
+
+ 1978-04-29
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sWOqPZzPTn9VvBR5LjuopIWYdh5aGzuX2vMjofhn8bStba1CDW1qkDdlYW4Rs/DfU/I1uqor4Lje
+/G3Yzh82yD0MHdzlW8MYUJ8RJe+czbjRUPaSbC/NRqhyF3eKnflxM++sJb2abrUH/9TV0q8P5QRS
+uZC/JpAEYpSazysPz/fv8AEnU8oxcTvCiax1jf2GZPmm3qFjPc4qDYNHqfnE8yWYt7kHeqPV/cRw
+x3aMGW8mRwQZb7VRFLW5g37nrt9N
+ AQAB
+
+
+
+
+
+
+
+
+
+
+
+ not(ancestor-or-self::pr:Identification)
+
+
+
+
+ b3d/wcQb0Bl0/6GSPsrMxWpdRLA=
+
+
+
+ eet0q3Thmw6+cbO1fazbEg0556I=
+
+
+
+oy55Cq7IyYy7z/TO2a3+m7tjG/ztiKhxhGzVqEYIWIObEOs/GVJDCCI4oe/HS8Fhc4TaXDcZXk4y
+qBp4JJ288TeaNjPYkPzp38nWJ4xRatEyo7VaySXy+TqgwiBT5uhxrwkroCr4ZIWwOvt1uR5UBVAf
+qk1ii+LPW2WYE3bMpoHfrM9CdFSPzWTRl/0zsEURc64EBPyIdKz+c70DaexeX2E0JVelKcj+jDaJ
+mHsFhi/9QoscqPEVA87qv07yhyK5S41+f3HDvpuhYwvQDdOq50sclfsI+g9r473VxiRsOmJ9Ak4/
+k2KP0tgfAQ+h5hRGQUUo5LYPywjg7zPxe8SGGA==
+
+
+
+
+MIIFZTCCBE2gAwIBAgIDAt4cMA0GCSqGSIb3DQEBBQUAMIGfMQswCQYDVQQGEwJB
+VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp
+bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMSIwIAYDVQQLDBlhLXNpZ24tY29y
+cG9yYXRlLWxpZ2h0LTAzMSIwIAYDVQQDDBlhLXNpZ24tY29ycG9yYXRlLWxpZ2h0
+LTAzMB4XDTA3MDExOTA5MDY0OFoXDTEyMDExOTA5MDY0OFowgZwxCzAJBgNVBAYT
+AkFUMRkwFwYDVQQKDBBCdW5kZXNrYW56bGVyYW10MR4wHAYDVQQLDBVEYXRlbnNj
+aHV0emtvbW1pc3Npb24xHTAbBgNVBAMMFERyLiBXYWx0cmF1dCBLb3RzY2h5MRUw
+EwYDVQQFEww3MDAyNDc0OTk4MDQxHDAaBgkqhkiG9w0BCQEWDWRza0Bkc2suZ3Yu
+YXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDfnQUhARo9o1FyCtTK
+d5VcXP2WvqSTIsiq19xtWcYF/4pMew/bHLD2DLeO9y5QFpfXJgmx2ySvj1dlzTXV
+ESzFAiF/uL1DbNjB3g00LV/AV4yRacCWEqGkSUN/RVUv9a+bFnK2vR4XZu8ORrcf
+9rpMg19JHZMWsJIT+BEBM4v0iPhboJ/lqoENZwHZW8W/3XAcOcNYfW95ZrsFH+M9
+6KEFlA9g4AP5CndSnozUeN5i1LJr0s3rz8U/c7O/KTkdTmnAeyLM01ST13jhGmjW
+R55wf1Hjt4PCxFf9zpF3FIHDJGyCImgR5ZZe9T6tAjo/ZKo16Huzq0Yy2OYtysDq
+WukzAgMBAAGjggGpMIIBpTATBgNVHSMEDDAKgAhBkWkcv63YmDBVBggrBgEFBQcB
+AQRJMEcwRQYIKwYBBQUHMAKGOWh0dHA6Ly93d3cuYS10cnVzdC5hdC9jZXJ0cy9h
+LXNpZ24tY29ycG9yYXRlLWxpZ2h0LTAzLmNydDBYBgNVHSAEUTBPME0GByooABEB
+BwEwQjBABggrBgEFBQcCARY0aHR0cDovL3d3dy5hLXRydXN0LmF0L2RvY3MvY3Av
+YS1zaWduLWNvcnBvcmF0ZS1saWdodDCBngYDVR0fBIGWMIGTMIGQoIGNoIGKhoGH
+bGRhcDovL2xkYXAuYS10cnVzdC5hdC9vdT1hLXNpZ24tY29ycG9yYXRlLWxpZ2h0
+LTAzLG89QS1UcnVzdCxjPUFUP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3Q/YmFz
+ZT9vYmplY3RjbGFzcz1laWRDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MBEGA1UdDgQK
+BAhMCA6eGvS1ujAOBgNVHQ8BAf8EBAMCBLAwCQYDVR0TBAIwADAOBgcqKAAKAQcB
+BAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAEoIvqPLAg0n2wCS27zTL+hmLi7zSbes
+Od4e6pFT1l3cwGfdTkhiHVPnPRaDGLQkS384fAXBrOp6W13X9m2jD9csO6vZhd+T
+nERXN1AqayoaecXFyHPykVUTLhn6pMdiSE21mEozfGLUDGMz74lvphEKFAOOCgp1
+o5ZCR09RbGAEbQNNn+ucXJxIa3mYjr1h3AElVbXoeoz12qUpqsNm9znymSkcmcNo
+B5Pk6qXXx9UeC/Tj0aTglNkcMOSCFayldzOBaY6+qWKguPdzQUEryhGiNuARQpM5
+KMzvI0rmpc4Gau5HT9rQZHadr++VS8v1k6935uIyyZF9s+gdS5ywnSM=
+
+
+
+
+
+
+
+
+ not(ancestor-or-self::dsig:Signature)
+
+
+
+ JZGwiDzQAtJtnJMeeXyypTrDjwY=
+
+
+
+
+
+
+
+
+
+
+
+
+ K2YMyx3/5kIpNJR+SAD/rbRYH+c=
+ urn:publicid:gv.at:wbpk+FN+www.act.at
+
+
+ Thomas
+ Knall
+
+ 1978-04-29
+
+
+
+
+ true
+
+
+ https://127.0.0.1:3496/https-security-layer-request
+
+
+ MIIEtDCCA5ygAwIBAgIDAgTEMA0GCSqGSIb3DQEBBQUAMIGXMQswCQYDVQQGEwJB
+VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp
+bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMR4wHAYDVQQLDBVhLXNpZ24tUHJl
+bWl1bS1TaWctMDIxHjAcBgNVBAMMFWEtc2lnbi1QcmVtaXVtLVNpZy0wMjAeFw0w
+NjA0MDQwOTUyMjhaFw0xMTA0MDQwOTUyMjhaMGkxCzAJBgNVBAYTAkFUMRUwEwYD
+VQQDDAxUaG9tYXMgS25hbGwxDjAMBgNVBAQMBUtuYWxsMQ8wDQYDVQQqDAZUaG9t
+YXMxFTATBgNVBAUTDDUzNTE5ODkyMzM0OTELMAkGA1UEDAwCREkwSTATBgcqhkjO
+PQIBBggqhkjOPQMBAQMyAARrnYW5sXCQ6M3irWaanDPi/ROXueKWiPRyZGjNH0Cp
+/NaiOuvrpv2RDVEKQm2tBiajggIPMIICCzATBgNVHSMEDDAKgAhN3+H/S9nJ3zAn
+BggrBgEFBQcBAwEB/wQYMBYwCAYGBACORgEBMAoGCCsGAQUFBwsBMHsGCCsGAQUF
+BwEBBG8wbTBCBggrBgEFBQcwAoY2aHR0cDovL3d3dy5hLXRydXN0LmF0L2NlcnRz
+L2Etc2lnbi1QcmVtaXVtLVNpZy0wMmEuY3J0MCcGCCsGAQUFBzABhhtodHRwOi8v
+b2NzcC5hLXRydXN0LmF0L29jc3AwWQYDVR0gBFIwUDBEBgYqKAARAQswOjA4Bggr
+BgEFBQcCARYsaHR0cDovL3d3dy5hLXRydXN0LmF0L2RvY3MvY3AvYS1zaWduLVBy
+ZW1pdW0wCAYGBACLMAEBMIGaBgNVHR8EgZIwgY8wgYyggYmggYaGgYNsZGFwOi8v
+bGRhcC5hLXRydXN0LmF0L291PWEtc2lnbi1QcmVtaXVtLVNpZy0wMixvPUEtVHJ1
+c3QsYz1BVD9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0P2Jhc2U/b2JqZWN0Y2xh
+c3M9ZWlkQ2VydGlmaWNhdGlvbkF1dGhvcml0eTARBgNVHQ4ECgQISNyH29WUoCgw
+DgYDVR0PAQH/BAQDAgbAMCgGA1UdCQQhMB8wHQYIKwYBBQUHCQExERgPMTk3ODA0
+MjkwMDAwMDBaMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADggEBAFkSCJE0YD4p
+4izU3ekQYPv4Z7gm/VFlpma5hXNvwkajVjHlAqo/ylYn8NQ4mMkD+yCDNtm8m8nr
+0K/yICb8Gnkbv59i6nh2AbzYBBb49VnYYGL6uunLH0aFUpAhy+3mDdlH8uhhIQBH
+wCfgwG1qa5zXY7bz4Vzkac/h6T+JVFkIegO8OHQDadhgJvW80qspiao2DTac6vVg
+x4tGvjpdmw1R2pXBYhHD5rkPHlkfGoeL3ak6hq4ea94Oy5VfNTIJv5MA0J2G1mwn
+W9B8uPWSM5EYPoWJyBOWcKBLSSUqOt9D/9215ZGfbchkdRZjx0dTAD3FIhgG8nA7
+2/uCFrBzyTk=
+
+
+
+
+ Prokura - MeineTestFirma
+ http://localhost:58080/omsp/OMSPRequest
+
+
+
+ K2YMyx3/5kIpNJR+SAD/rbRYH+c=
+ urn:publicid:gv.at:wbpk+FN+www.act.at
+
+
+ Thomas
+ Knall
+
+ 1978-04-29
+
+
+
+
+
+ 123456i
+ urn:publicid:gv.at:baseid+XFN
+
+ MeineTestFirma
+
+
+
+ Wien
+ 2008-07-14
+
+
+ false
+
+
+ Der/Die Bevollmächtigte wird zum Prokuristen/Prokuristin bestellt.
+
+
+
+
+
+
+
+
+ not(ancestor-or-self::pr:Identification or ancestor-or-self::dsig:Signature)
+
+
+
+
+
+ PRRF0sWBgoywztCKWEXafZfhpd0=
+
+
+
+ NorNorUqPFMA06JfxSJopOq7Qv0=
+
+
+ IQMZFc57XZd9LjeiaZqSfzZtWuXhuikAqbKA7pWuDK02DLFSYZPXsGjcvnwNdVaP
+
+
+ MIICtjCCAm6gAwIBAgIBATAJBgcqhkjOPQQBMGoxCzAJBgNVBAYTAkFUMQ0wCwYD
+VQQHEwRXaWVuMRkwFwYDVQQJExBFc3NsaW5nZ2Fzc2UgNS85MQwwCgYDVQQKEwNB
+Q1QxIzAhBgNVBAMTGlZvbGxtYWNodGVuIFNpZ25hdHVyZGllbnN0MB4XDTA4MDcw
+ODE1MTk1MFoXDTEyMTIzMTIxNTk1OVowajELMAkGA1UEBhMCQVQxDTALBgNVBAcT
+BFdpZW4xGTAXBgNVBAkTEEVzc2xpbmdnYXNzZSA1LzkxDDAKBgNVBAoTA0FDVDEj
+MCEGA1UEAxMaVm9sbG1hY2h0ZW4gU2lnbmF0dXJkaWVuc3QwgfMwgbwGByqGSM49
+AgEwgbACAQEwJAYHKoZIzj0BAQIZAP////////////////////7//////////zA0
+BBj////////////////////+//////////wEGGQhBRnlnIDnD6fpq3IkMEn+uN7s
+wUa5sQQxBBiNqA6wMJD2fL8g60OhiAD0/wr9gv8QEgcZK5X/yNp4YxAR7WskzdVz
++XehHnlIEQIZAP///////////////5ne+DYUa8mxtNIoMQIBAQMyAAS908G9FD5/
+LLYruwFbp9giXahdQ1FAqKwzohSn9pgsVTQBnvXxU8IWIzhPHs49DZCjazBpMAwG
+A1UdEwEB/wQCMAAwHQYDVR0OBBYEFLOSgnkLSJ3l4Ah49rHX/FAV1wWcMBkGA1Ud
+IAQSMBAwDgYMKwYBBAGVEgECBAEBMB8GA1UdIwQYMBaAFLOSgnkLSJ3l4Ah49rHX
+/FAV1wWcMAkGByqGSM49BAEDNwAwNAIYTTppZzS6wqoLDFcf9frHzf1kMheY04dT
+Ahg4Nrb54vE3DTRf9sbO4xs4dTARHSt1ihA=
+
+
+
+
+
+
+
+ not(ancestor-or-self::dsig:Signature)
+
+
+
+
+
+ oz6ThHPL3V7RNibfPrDSWVhUgi8=
+
+
+
+
+
+
+
+
+
diff --git a/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/task/SignedAuthBlock.xml b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/task/SignedAuthBlock.xml
new file mode 100644
index 000000000..450ba90f3
--- /dev/null
+++ b/id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/process/spring/test/task/SignedAuthBlock.xml
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Signatur der Anmeldedaten
+
+
+
+ Signatur der Anmeldedaten
+
+ Mit meiner elektronischen Signatur beantrage ich,
+
+
+ , geboren am
+.
+.
+,
+
+in der Rolle als
+(OID***= ),
+
+den Zugang zur gesicherten Anwendung.
+
+
+ Datum und Uhrzeit:
+.
+.
+,
+:
+:
+
+
+
+ HPI(**):
+
+
+
+ wbPK(*):
+
+
+
+
+ Ich bin weiters ermächtigt als
+von
+ , geboren am
+ .
+ .
+
+
+ ,
+
+ , in deren Auftrag zu handeln.
+
+
+ wbPK(*) des Vollmachtgebers:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (*) wbPK: Das wirtschaftsbereichsspezifische Personenkennzeichen wird aus den
+jeweiligen Stammzahlen des Bürgers und des Wirtschaftsunternehmens berechnet und ermöglicht eine eindeutige Zuordnung des Bürgers zum
+Wirtschaftsunternehmen.
+
+
+ (**) HPI: Der eHealth Professional Identifier wird aus den jeweiligen
+Stammzahlen der Gesundheitsdiensteanbieterinnen / Gesundheitsdiensteanbieter berechnet und ermöglicht eine eindeutige Zuordnung der
+Gesundheitsdiensteanbieterin / des Gesundheitsdiensteanbieters im Gesundheitsbereich.
+
+
+ (***) OID: Object Identifier sind standardisierte Objekt-Bezeichner und
+beschreiben eindeutig die Rollen des GDA-Token Inhabers.
+
+
+
+
+
+
+
+
+
+ 0q9QWyqAyyiVNNLu1rIcU+nKsEE=
+
+
+
+ WtB0/ptvoB/r/7+fauSUIBULymg=
+
+
+ mZt9DuZiDqG81scsf30qjSDdy6vKC2/n034ZZwMUAvfWOXy3+Ubsk5X5CHhz
++lyI
+
+
+ MIIEtDCCA5ygAwIBAgIDAgTEMA0GCSqGSIb3DQEBBQUAMIGXMQswCQYDVQQG
+EwJBVDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lz
+dGVtZSBpbSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMR4wHAYDVQQLDBVh
+LXNpZ24tUHJlbWl1bS1TaWctMDIxHjAcBgNVBAMMFWEtc2lnbi1QcmVtaXVt
+LVNpZy0wMjAeFw0wNjA0MDQwOTUyMjhaFw0xMTA0MDQwOTUyMjhaMGkxCzAJ
+BgNVBAYTAkFUMRUwEwYDVQQDDAxUaG9tYXMgS25hbGwxDjAMBgNVBAQMBUtu
+YWxsMQ8wDQYDVQQqDAZUaG9tYXMxFTATBgNVBAUTDDUzNTE5ODkyMzM0OTEL
+MAkGA1UEDAwCREkwSTATBgcqhkjOPQIBBggqhkjOPQMBAQMyAARrnYW5sXCQ
+6M3irWaanDPi/ROXueKWiPRyZGjNH0Cp/NaiOuvrpv2RDVEKQm2tBiajggIP
+MIICCzATBgNVHSMEDDAKgAhN3+H/S9nJ3zAnBggrBgEFBQcBAwEB/wQYMBYw
+CAYGBACORgEBMAoGCCsGAQUFBwsBMHsGCCsGAQUFBwEBBG8wbTBCBggrBgEF
+BQcwAoY2aHR0cDovL3d3dy5hLXRydXN0LmF0L2NlcnRzL2Etc2lnbi1QcmVt
+aXVtLVNpZy0wMmEuY3J0MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5hLXRy
+dXN0LmF0L29jc3AwWQYDVR0gBFIwUDBEBgYqKAARAQswOjA4BggrBgEFBQcC
+ARYsaHR0cDovL3d3dy5hLXRydXN0LmF0L2RvY3MvY3AvYS1zaWduLVByZW1p
+dW0wCAYGBACLMAEBMIGaBgNVHR8EgZIwgY8wgYyggYmggYaGgYNsZGFwOi8v
+bGRhcC5hLXRydXN0LmF0L291PWEtc2lnbi1QcmVtaXVtLVNpZy0wMixvPUEt
+VHJ1c3QsYz1BVD9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0P2Jhc2U/b2Jq
+ZWN0Y2xhc3M9ZWlkQ2VydGlmaWNhdGlvbkF1dGhvcml0eTARBgNVHQ4ECgQI
+SNyH29WUoCgwDgYDVR0PAQH/BAQDAgbAMCgGA1UdCQQhMB8wHQYIKwYBBQUH
+CQExERgPMTk3ODA0MjkwMDAwMDBaMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEF
+BQADggEBAFkSCJE0YD4p4izU3ekQYPv4Z7gm/VFlpma5hXNvwkajVjHlAqo/
+ylYn8NQ4mMkD+yCDNtm8m8nr0K/yICb8Gnkbv59i6nh2AbzYBBb49VnYYGL6
+uunLH0aFUpAhy+3mDdlH8uhhIQBHwCfgwG1qa5zXY7bz4Vzkac/h6T+JVFkI
+egO8OHQDadhgJvW80qspiao2DTac6vVgx4tGvjpdmw1R2pXBYhHD5rkPHlkf
+GoeL3ak6hq4ea94Oy5VfNTIJv5MA0J2G1mwnW9B8uPWSM5EYPoWJyBOWcKBL
+SSUqOt9D/9215ZGfbchkdRZjx0dTAD3FIhgG8nA72/uCFrBzyTk=
+
+
+
+
+
+
+
+ 2008-07-14T15:51:35Z
+
+
+
+
+ inMYWBmAxMHP7mDENjLFaEtv0Zk=
+
+
+ CN=a-sign-Premium-Sig-02,OU=a-sign-Premium-Sig-02,O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH,C=AT
+ 132292
+
+
+
+
+
+
+
+
+
+ application/xhtml+xml
+
+
+
+
+
+
\ No newline at end of file
--
cgit v1.2.3
From 8579cf80c3602f963566d31eaf04f59f68d3bf11 Mon Sep 17 00:00:00 2001
From: Thomas Knall
Date: Thu, 29 Jan 2015 10:56:18 +0100
Subject: Add STORK process (MOAID-58).
- Add STORKAuthentication.process.xml
- Add PepsConnectorTask using code from PEPSConnectorServlet.
- Split code from PEPSConnectorWithLocalSigningServlet into PepsConnectorHandleResponseWithoutSignatureTask and PepsConnectorHandleLocalSignResponseTask.
- Replace SpringExpressionEvaluator within applicationContext.xml with SpringWebExpressionEvaluator (allowing expressions using request parameter(s)).
- Make servlet mappings /PEPSConnectorWithLocalSigning and /PEPSConnector point to the process engine signaling servlet.
- Add many FIXMEs marking problematic code.
- Move code to start stork authentication from StartAuthenticationBuilder to CreateStorkAuthRequestFormTask.
- Mark PEPSConnectorServlet and PEPSConnectorWithLocalSigningServlet deprecated.
- Remove @author tknall from classes assembled using existing (bogus) code.
---
.../src/main/webapp/WEB-INF/applicationContext.xml | 2 +-
id/server/auth/src/main/webapp/WEB-INF/web.xml | 24 +-
.../moa/id/auth/AuthenticationServer.java | 13 +-
.../auth/builder/StartAuthenticationBuilder.java | 28 +-
.../moa/id/auth/servlet/PEPSConnectorServlet.java | 1 +
.../PEPSConnectorWithLocalSigningServlet.java | 1 +
.../moa/id/auth/tasks/AbstractAuthServletTask.java | 3 -
.../id/auth/tasks/CertificateReadRequestTask.java | 5 +-
.../id/auth/tasks/CreateIdentityLinkFormTask.java | 1 -
.../moa/id/auth/tasks/GetForeignIDTask.java | 1 -
.../moa/id/auth/tasks/GetMISSessionIDTask.java | 1 -
.../auth/tasks/PrepareAuthBlockSignatureTask.java | 1 -
.../auth/tasks/VerifyAuthenticationBlockTask.java | 1 -
.../moa/id/auth/tasks/VerifyCertificateTask.java | 1 -
.../moa/id/auth/tasks/VerifyIdentityLinkTask.java | 9 +-
.../AbstractPepsConnectorWithLocalSigningTask.java | 258 ++++++++++
.../stork/CreateStorkAuthRequestFormTask.java | 114 +++++
.../PepsConnectorHandleLocalSignResponseTask.java | 218 ++++++++
...onnectorHandleResponseWithoutSignatureTask.java | 441 ++++++++++++++++
.../moa/id/auth/tasks/stork/PepsConnectorTask.java | 567 +++++++++++++++++++++
.../processes/DefaultAuthentication.process.xml | 4 +-
.../processes/STORKAuthentication.process.xml | 29 ++
.../resources/properties/id_messages_de.properties | 3 +
23 files changed, 1656 insertions(+), 70 deletions(-)
create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/tasks/stork/AbstractPepsConnectorWithLocalSigningTask.java
create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/tasks/stork/CreateStorkAuthRequestFormTask.java
create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/tasks/stork/PepsConnectorHandleLocalSignResponseTask.java
create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/tasks/stork/PepsConnectorHandleResponseWithoutSignatureTask.java
create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/tasks/stork/PepsConnectorTask.java
create mode 100644 id/server/idserverlib/src/main/resources/resources/processes/STORKAuthentication.process.xml
(limited to 'id/server/idserverlib/src')
diff --git a/id/server/auth/src/main/webapp/WEB-INF/applicationContext.xml b/id/server/auth/src/main/webapp/WEB-INF/applicationContext.xml
index 0f9f05baa..8e210c040 100644
--- a/id/server/auth/src/main/webapp/WEB-INF/applicationContext.xml
+++ b/id/server/auth/src/main/webapp/WEB-INF/applicationContext.xml
@@ -11,7 +11,7 @@
-
+
diff --git a/id/server/auth/src/main/webapp/WEB-INF/web.xml b/id/server/auth/src/main/webapp/WEB-INF/web.xml
index 4548e05d9..2dbceb4e9 100644
--- a/id/server/auth/src/main/webapp/WEB-INF/web.xml
+++ b/id/server/auth/src/main/webapp/WEB-INF/web.xml
@@ -119,28 +119,6 @@
/services/*