diff options
| author | Christian Wagner <c.wagner@datentechnik-innovation.com> | 2015-01-29 08:18:00 +0100 | 
|---|---|---|
| committer | Christian Wagner <c.wagner@datentechnik-innovation.com> | 2015-01-29 08:18:00 +0100 | 
| commit | d45b41a740a6267c78a6ea27b7617c3d317db837 (patch) | |
| tree | 9f165ae789b1bb8a076dfd1b523240d31d07be5b | |
| parent | 7ae32988fcf9e4407b4bcae7831772338da55a8f (diff) | |
| download | moa-id-spss-d45b41a740a6267c78a6ea27b7617c3d317db837.tar.gz moa-id-spss-d45b41a740a6267c78a6ea27b7617c3d317db837.tar.bz2 moa-id-spss-d45b41a740a6267c78a6ea27b7617c3d317db837.zip | |
integrate process engine from project 'dti-process-engine' - INCOMPLETE!
  - commit neccessary in order to avoid blocking the development process
additional small fix due to earlier package renaming
35 files changed, 2886 insertions, 9 deletions
| 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 a4a06d24a..ce8fe8971 100644 --- a/id/server/auth/src/main/webapp/WEB-INF/applicationContext.xml +++ b/id/server/auth/src/main/webapp/WEB-INF/applicationContext.xml @@ -9,16 +9,18 @@  	<context:annotation-config />
 -	<bean id="processEngine" class="com.datentechnik.process_engine.ProcessEngineImpl">
 +	<bean id="processEngine" class="at.gv.egovernment.moa.id.process.ProcessEngineImpl">
  		<property name="transitionConditionExpressionEvaluator">
  			<bean class="com.datentechnik.process_engine.spring.SpringExpressionEvaluator" />
  		</property>
  		<property name="processInstanceMaxIdleTimeSeconds" value="600" />
 +	<!--
  		<property name="processDefinitions">
  			<bean class="com.datentechnik.process_engine.spring.ProcessDefinitionsFactoryBean">
  				<property name="resources" value="classpath:resources/processes/*.process.xml" />
  			</bean>
  		</property>
 +	-->
  	</bean>
  	<task:scheduler id="taskScheduler" pool-size="1" />
 @@ -27,5 +29,5 @@  	</task:scheduled-tasks>
  	<bean id="authenticationManager" class="at.gv.egovernment.moa.id.moduls.AuthenticationManager" factory-method="getInstance" />
 -	<bean id="moduleRegistration" class="at.gv.egovernment.moa.id.moduls.modulregistration.ModuleRegistration" factory-method="getInstance" />
 +	<bean id="moduleRegistration" class="at.gv.egovernment.moa.id.moduls.moduleregistration.ModuleRegistration" factory-method="getInstance" />
  </beans>
 diff --git a/id/server/idserverlib/pom.xml b/id/server/idserverlib/pom.xml index 530e00d74..0b3319111 100644 --- a/id/server/idserverlib/pom.xml +++ b/id/server/idserverlib/pom.xml @@ -407,11 +407,6 @@  		</dependency>
  		<dependency>
 -			<groupId>com.datentechnik.process-engine</groupId>
 -			<artifactId>dti-process-engine-spring-web</artifactId>
 -			<version>${com.datentechnik.process-engine.version}</version>
 -		</dependency>
 -		<dependency>
  			<groupId>javax.servlet</groupId>
  			<artifactId>javax.servlet-api</artifactId>
  			<scope>provided</scope>
 diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExecutionContextImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExecutionContextImpl.java new file mode 100644 index 000000000..87ee57a24 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExecutionContextImpl.java @@ -0,0 +1,79 @@ +package at.gv.egovernment.moa.id.process; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.datentechnik.process_engine.api.ExecutionContext; + +/** + * ExecutionContext implementation, related to a certain process instance. + *  + * @author tknall + *  + */ +public class ExecutionContextImpl implements ExecutionContext { + +	private static final long serialVersionUID = 1L; + +	private Map<String, Serializable> ctxData = Collections.synchronizedMap(new HashMap<String, Serializable>()); + +	private String processInstanceId; + +	/** +	 * Creates a new instance. +	 */ +	public ExecutionContextImpl() { +	} + +	/** +	 * Creates a new instance and associated it with a certain process instance. +	 */ +	public ExecutionContextImpl(String processInstanceId) { +		this.processInstanceId = processInstanceId; +	} + +	@Override +	public void setProcessInstanceId(String processInstanceId) { +		this.processInstanceId = processInstanceId; +	} + +	@Override +	public String getProcessInstanceId() { +		return processInstanceId; +	} + +	@Override +	public Serializable get(String key) { +		return ctxData.get(key); +	} + +	@Override +	public Serializable remove(String key) { +		return ctxData.remove(key); +	} + +	@Override +	public void put(String key, Serializable object) { +		ctxData.put(key, object); +	} + +	@Override +	public Set<String> keySet() { +		return Collections.unmodifiableSet(ctxData.keySet()); +	} + +	@Override +	public String toString() { +		StringBuilder builder = new StringBuilder(); +		builder.append("ExecutionContextImpl ["); +		builder.append("id=").append(processInstanceId); +		builder.append(", variables="); +		builder.append(ctxData.keySet()); +		builder.append("]"); +		return builder.toString(); +	} + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExpressionEvaluationContextImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExpressionEvaluationContextImpl.java new file mode 100644 index 000000000..acc10449f --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ExpressionEvaluationContextImpl.java @@ -0,0 +1,44 @@ +package at.gv.egovernment.moa.id.process; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.datentechnik.process_engine.api.ExecutionContext; +import com.datentechnik.process_engine.api.ExpressionEvaluationContext; + +/** + * Context implementation used for expression evaluation only. + *  + * @author tknall + *  + */ +public class ExpressionEvaluationContextImpl implements ExpressionEvaluationContext { + +	private static final long serialVersionUID = 1L; + +	private Map<String, Serializable> ctxData; + +	/** +	 * Creates a new instance and initializes it with data from a given process instance. +	 *  +	 * @param processInstance +	 *            The process instance. +	 */ +	ExpressionEvaluationContextImpl(ProcessInstance processInstance) { +		ExecutionContext executionContext = processInstance.getExecutionContext(); +		Set<String> keys = executionContext.keySet(); +		ctxData = Collections.synchronizedMap(new HashMap<String, Serializable>(keys.size())); +		for (String key : keys) { +			ctxData.put(key, executionContext.get(key)); +		} +	} + +	@Override +	public Map<String, Serializable> 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. + * <p/ + * The parser is thread-safe. + * @author tknall + * + */ +public class ProcessDefinitionParser { +	 +	private static final String NS = "http://www.datentechnik.com/process-engine/processdefinition/v1"; +	 +	private static Logger log = LoggerFactory.getLogger(ProcessDefinitionParser.class); + +	private static class LazyProcessDefinitionSchemaHolder { +		private static final Schema PD_SCHEMA_INSTANCE; +		static { +			try (InputStream in = ProcessDefinitionParser.class.getResourceAsStream("ProcessDefinition.xsd")) { +				log.trace("Compiling process definition schema."); +				SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); +				// schema is thread-safe +				PD_SCHEMA_INSTANCE = factory.newSchema(new StreamSource(in)); +			} catch (Exception e) { +				throw new RuntimeException("Unable to compile process definition schema.", e); +			} +		} +	} + +	/** +	 * Parses an XML representation of a process definition. The representation is being validated in order to suffice +	 * the related XML schema. +	 *  +	 * @param processDefinitionInputStream +	 *            The process definition. +	 * @return A new process definition. +	 * @throws ProcessDefinitionParserException +	 *             Thrown in case of error parsing the process definition. +	 */ +	public ProcessDefinition parse(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException { +		XMLEventReader reader = null; +		final ProcessDefinition pd = new ProcessDefinition(); +		log.debug("Parsing and validating process definition."); +		try { + +			// Standard implementation of XMLInputFactory seems not to be thread-safe +			XMLInputFactory inputFactory = XMLInputFactory.newInstance(); +			reader = inputFactory.createXMLEventReader(processDefinitionInputStream); + +			final List<StartElement> transitionElements = new ArrayList<>(); +			final List<StartEvent> 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<StartElement> 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. +	 * <p/> +	 * 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. +	 * <p/> +	 * 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<String, ProcessDefinition> processDefinitions = new ConcurrentHashMap<String, ProcessDefinition>(); +	private Map<String, ProcessInstance> processInstances = new ConcurrentHashMap<String, ProcessInstance>(); +	 +	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<ProcessDefinition> 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. +	 * <p/> +	 * 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<Entry<String, ProcessInstance>> it = processInstances.entrySet().iterator(); +		while (it.hasNext()) { +			Entry<String, ProcessInstance> 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<Transition>() { +			@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<ProcessInstance> 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.<p/> +	 * 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.<p/> +	 * 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<String> 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<String, Serializable> 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 + * <ul> + * <li>a {@link StartEvent},</li> + * <li>one or more {@linkplain TaskInfo Tasks},</li> + * <li>one or more {@linkplain EndEvent EndEvents} and</li> + * <li>some {@linkplain Transition Transitions} linking StartEvents, Tasks and EndEvents. + * </ul> + *  + * @author tknall + *  + */ +public class ProcessDefinition { + +	private String id; +	private StartEvent startEvent; +	private Map<String, TaskInfo> taskInfos = new LinkedHashMap<>(); +	private Map<String, EndEvent> 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<String, TaskInfo> getTaskInfos() { +		return taskInfos; +	} + +	/** +	 * Sets the map containing the tasks. +	 *  +	 * @param taskInfos +	 *            The map containing the tasks. +	 */ +	public void setTaskInfos(Map<String, TaskInfo> 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<String, EndEvent> 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<String, EndEvent> 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<Transition> outgoingTransitions = new ArrayList<>(); +	private List<Transition> 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<Transition> 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<Transition> 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<Transition> 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<Transition> 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. +	 * <p/>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}. + * <p/> + * Note that this abstract task requires the Spring (web) framework including a {@link RequestContextFilter} to be set + * within {@code web.xml}. + *  + * <pre> + * ... + * <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> + * ... + * </pre> + *  + * @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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" +	targetNamespace="http://www.datentechnik.com/process-engine/processdefinition/v1" +	xmlns:tns="http://www.datentechnik.com/process-engine/processdefinition/v1" +	elementFormDefault="qualified" version="1.0"> + +	<xsd:element name="ProcessDefinition"> +		<xsd:complexType> +			<xsd:sequence> +				<xsd:choice minOccurs="0" maxOccurs="unbounded"> +					<xsd:element name="StartEvent" type="tns:StartEventType" /> +					<xsd:element name="Task" type="tns:TaskType" /> +					<xsd:element name="Transition" type="tns:TransitionType" /> +					<xsd:element name="EndEvent" type="tns:EndEventType" /> +				</xsd:choice> +			</xsd:sequence> +			<xsd:attribute name="id" type="xsd:ID" use="required" /> +		</xsd:complexType> +	</xsd:element> + +	<xsd:complexType name="ProcessNodeType" abstract="true"> +		<xsd:attribute name="id" type="xsd:ID" use="required" /> +	</xsd:complexType> + +	<xsd:complexType name="StartEventType"> +		<xsd:complexContent> +			<xsd:extension base="tns:ProcessNodeType" /> +		</xsd:complexContent> +	</xsd:complexType> + +	<xsd:complexType name="TransitionType"> +		<xsd:attribute name="from" type="xsd:IDREF" use="required" /> +		<xsd:attribute name="to" type="xsd:IDREF" use="required" /> +		<xsd:attribute name="id" type="xsd:ID" /> +		<xsd:attribute name="conditionExpression" type="xsd:string" /> +	</xsd:complexType> + +	<xsd:complexType name="EndEventType"> +		<xsd:complexContent> +			<xsd:extension base="tns:ProcessNodeType" /> +		</xsd:complexContent> +	</xsd:complexType> + +	<xsd:complexType name="TaskType"> +		<xsd:complexContent> +			<xsd:extension base="tns:ProcessNodeType"> +				<xsd:attribute name="async" type="xsd:boolean" default="false"/> +				<xsd:attribute name="class" type="xsd:string" /> +			</xsd:extension> +		</xsd:complexContent> +	</xsd:complexType> + +</xsd:schema> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<pd:ProcessDefinition xmlns:pd="http://www.datentechnik.com/process-engine/processdefinition/v1" +	id="SampleProcessDefinitionForSAML1Authentication"> + +	<!-- +		returns String 'bkuURL' +	--> +	<pd:Task id="bkuSelectionTask" class="com.datentechnik.process_engine.spring.test.task.SelectBKUTask" /> + +	<!-- +		requires 'bkuURL' +		returns String 'IdentityLink' +	--> +	<pd:Task id="getIdentityLinkTask" class="com.datentechnik.process_engine.spring.test.task.GetIdentityLinkTask" /> + +	<!-- +		requires 'IdentityLink' +		returns Boolean 'isIdentityLinkValidated' +	--> +	<pd:Task id="validateIdentityLinkTask" class="com.datentechnik.process_engine.spring.test.task.ValidateIdentityLinkTask" /> + +	<!-- +		requires 'IdentityLink', 'isIdentityLinkValidated', 'bkuURL' +		returns String 'SignedAuthBlock' +	--> +	<pd:Task id="signAuthBlockTask" class="com.datentechnik.process_engine.spring.test.task.SignAuthBlockTask" /> + +	<!-- +		requires 'IdentityLink', 'isIdentityLinkValidated', 'SignedAuthBlock' +		returns Boolean 'isSignedAuthBlockValidated' +	--> +	<pd:Task id="validateSignedAuthBlockTask" class="com.datentechnik.process_engine.spring.test.task.ValidateSignedAuthBlockTask" /> +	 +	<!-- +		requires 'IdentityLink', 'isIdentityLinkValidated', 'SignedAuthBlock', 'isSignedAuthBlockValidated'; +		returns 'SAML1Assertion' +	--> +	<pd:Task id="createAssertionTask" class="com.datentechnik.process_engine.spring.test.task.CreateSAML1AssertionTask" /> + +	<pd:StartEvent id="start" /> +	<pd:EndEvent id="end" /> + +	<pd:Transition from="start" to="bkuSelectionTask"    conditionExpression="ctx['bkuURL'] == null" /> +	<pd:Transition from="start" to="getIdentityLinkTask"  /> +	 +	<pd:Transition from="bkuSelectionTask"            to="getIdentityLinkTask" /> +	<pd:Transition from="getIdentityLinkTask"         to="validateIdentityLinkTask" /> +	<pd:Transition from="validateIdentityLinkTask"    to="signAuthBlockTask"            conditionExpression="ctx['isIdentityLinkValidated']" /> +	<pd:Transition from="signAuthBlockTask"           to="validateSignedAuthBlockTask" /> +	<pd:Transition from="validateSignedAuthBlockTask" to="createAssertionTask"          conditionExpression="ctx['isSignedAuthBlockValidated']" /> +	 +	<pd:Transition from="createAssertionTask" to="end" /> + +</pd:ProcessDefinition> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<pd:ProcessDefinition xmlns:pd="http://www.datentechnik.com/process-engine/processdefinition/v1" +	id="SampleProcessWithExpression1"> + +	<pd:Task id="task1" /> +	<pd:Task id="task2" /> +	<pd:Task id="task3" /> +	<pd:Task id="task4" /> + +	<pd:StartEvent id="start" /> +	<pd:EndEvent id="end" /> + +	<pd:Transition from="start" to="task1" conditionExpression="'true'" /> +	<pd:Transition from="task1" to="task2" conditionExpression="'true'" /> +	<pd:Transition from="task2" to="task3" conditionExpression="'true'" /> +	<pd:Transition from="task3" to="task4" conditionExpression="'true'" /> +	<pd:Transition from="task4" to="end"   conditionExpression="'true'" /> +	 +</pd:ProcessDefinition> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" +	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +	xmlns:task="http://www.springframework.org/schema/task" +	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd +		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> + +	<bean id="springElAwareExpressionEvaluator" class="com.datentechnik.process_engine.spring.SpringExpressionEvaluator" /> +	 +	<bean id="processEngine" class="com.datentechnik.process_engine.ProcessEngineImpl"> +		<property name="transitionConditionExpressionEvaluator" ref="springElAwareExpressionEvaluator" /> +		<property name="processInstanceMaxIdleTimeSeconds" value="600" /> +		<property name="processDefinitions"> +			<list> +				<bean class="com.datentechnik.process_engine.spring.ProcessDefinitionFactoryBean"> +					<property name="resource" value="classpath:com/datentechnik/process_engine/spring/test/SampleProcessDefinitionWithExpression1.xml" /> +				</bean> +				<bean class="com.datentechnik.process_engine.spring.ProcessDefinitionFactoryBean"> +					<property name="resource" value="classpath:com/datentechnik/process_engine/spring/test/SampleProcessDefinitionForSAML1Authentication.xml" /> +				</bean> +			</list> +		</property> +	</bean> +	 +	<task:scheduler id="taskScheduler" pool-size="1" /> +	<task:scheduled-tasks scheduler="taskScheduler"> +		<task:scheduled ref="processEngine" method="cleanup" fixed-delay="60000" /> +	</task:scheduled-tasks> + +</beans> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" +	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> + +	<bean id="simplePojo" class="com.datentechnik.process_engine.spring.test.SimplePojo"> +		<property name="booleanValue" value="true" /> +		<property name="integerValue" value="42" /> +		<property name="stringValue" value="HelloWorld" /> +	</bean> +	 +	<bean id="expressionEvaluator" class="com.datentechnik.process_engine.spring.SpringExpressionEvaluator" /> + +</beans> 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 @@ +<?xml version="1.0" encoding="UTF-8"?><saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:ecdsa="http://www.w3.org/2001/04/xmldsig-more#" xmlns:pr="http://reference.e-government.gv.at/namespace/persondata/20020228#" xmlns:si="http://www.w3.org/2001/XMLSchema-instance" AssertionID="szr.bmi.gv.at-AssertionID132860852347311974" IssueInstant="2012-02-07T10:55:23+01:00" Issuer="http://portal.bmi.gv.at/ref/szr/issuer" MajorVersion="1" MinorVersion="0"> +	<saml:AttributeStatement> +		<saml:Subject> +			<saml:SubjectConfirmation> +				<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</saml:ConfirmationMethod> +				<saml:SubjectConfirmationData> +					<pr:Person si:type="pr:PhysicalPersonType"><pr:Identification><pr:Value>tqCQEC7+AqGEeeL390V5Jg==</pr:Value><pr:Type>urn:publicid:gv.at:baseid</pr:Type></pr:Identification><pr:Name><pr:GivenName>Max</pr:GivenName><pr:FamilyName primary="undefined">Mustermann</pr:FamilyName></pr:Name><pr:DateOfBirth>1940-01-01</pr:DateOfBirth></pr:Person> +				</saml:SubjectConfirmationData> +			</saml:SubjectConfirmation> +		</saml:Subject> +	<saml:Attribute AttributeName="CitizenPublicKey" AttributeNamespace="urn:publicid:gv.at:namespaces:identitylink:1.2"><saml:AttributeValue><ecdsa:ECDSAKeyValue><ecdsa:DomainParameters><ecdsa:NamedCurve URN="urn:oid:1.2.840.10045.3.1.7"/></ecdsa:DomainParameters><ecdsa:PublicKey><ecdsa:X Value="111409151487007036894649069746411000129419717653159596280366627647453458115517" si:type="ecdsa:PrimeFieldElemType"/><ecdsa:Y Value="94725036374184689337892465478597728884477416796494369571140658859618867645034" si:type="ecdsa:PrimeFieldElemType"/></ecdsa:PublicKey></ecdsa:ECDSAKeyValue></saml:AttributeValue></saml:Attribute></saml:AttributeStatement> +	<dsig:Signature> +		<dsig:SignedInfo> +			<dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> +			<dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> +			<dsig:Reference URI=""> +				<dsig:Transforms> +					<dsig:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> +						<dsig:XPath>not(ancestor-or-self::pr:Identification)</dsig:XPath> +					</dsig:Transform> +					<dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> +				</dsig:Transforms> +				<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +				<dsig:DigestValue>Rmr5vkWXL/PvpoXnbK632QmzYms=</dsig:DigestValue> +			</dsig:Reference> +			<dsig:Reference Type="http://www.w3.org/2000/09/xmldsig#Manifest" URI="#manifest"> +				<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +				<dsig:DigestValue>HoPZWYll8aMFpKOlRSwckt5iCQk=</dsig:DigestValue> +			</dsig:Reference> +		</dsig:SignedInfo> +		<dsig:SignatureValue> +    NPpRwVo5/5kf5iHUyaEc7d7So3W4oPgOCYNgnKpgdZfttFkFFN+9oG60w7YvKEYSeTPhP3zp7eaH +ZFapj+naD+wd0y5ELWep9Y+s+qP7fNLrFECHQxQasLWtR4akxlWDpYQ0bvOuepK2ip1EQ6pRlccA +wJ1l4iOWFhfdA9YAg5QLkBqWSwgrNUswhLnDBM+Ot6Gj5g2rpYY7aoAOXvTR8B5Dkg94ASb4u0wv +VPV8+4mjOfP+l6QWLqywzcq3qj/qFZkbujjZbV/fNPDnDD1ff/M6ZfCGO8xzlYfjfEA7cmHuiJf2 +/ey/3nT7vI5XbpBPWChT5Sl4DQysxlfE6e4MZw== +  </dsig:SignatureValue><dsig:KeyInfo><dsig:X509Data><dsig:X509Certificate>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=</dsig:X509Certificate></dsig:X509Data></dsig:KeyInfo> +		<dsig:Object> +			<dsig:Manifest Id="manifest"> +				<dsig:Reference URI=""> +					<dsig:Transforms> +						<dsig:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> +							<dsig:XPath>not(ancestor-or-self::dsig:Signature)</dsig:XPath> +						</dsig:Transform> +					</dsig:Transforms> +					<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +					<dsig:DigestValue>7IkIdYti2dh3VZQ4Fp+9lPT67cM=</dsig:DigestValue> +				</dsig:Reference> +			</dsig:Manifest> +		</dsig:Object> +	</dsig:Signature> +</saml:Assertion>
\ 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<saml:Assertion AssertionID="6025428631468682100" IssueInstant="2008-07-14T17:51:38+02:00" Issuer="https://localhost:18443/moa-id-auth/" MajorVersion="1" MinorVersion="0" xmlns:pr="http://reference.e-government.gv.at/namespace/persondata/20020228#" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:si="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +  <saml:AttributeStatement> +	 <saml:Subject> +		<saml:NameIdentifier NameQualifier="urn:publicid:gv.at:wbpk+FN+www.act.at">K2YMyx3/5kIpNJR+SAD/rbRYH+c=</saml:NameIdentifier> +		<saml:SubjectConfirmation> +		  <saml:ConfirmationMethod>http://reference.e-government.gv.at/namespace/moa/20020822#cm</saml:ConfirmationMethod> +		  <saml:SubjectConfirmationData> +			 <saml:Assertion AssertionID="any" IssueInstant="2008-07-14T17:51:26+02:00" Issuer="Thomas Knall" MajorVersion="1" MinorVersion="0" xmlns:pr="http://reference.e-government.gv.at/namespace/persondata/20020228#" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"> +				<saml:AttributeStatement> +				  <saml:Subject> +					 <saml:NameIdentifier>https://localhost:18443/moa-id-auth/</saml:NameIdentifier> +				  </saml:Subject> +				  <saml:Attribute AttributeName="wbPK" AttributeNamespace="http://reference.e-government.gv.at/namespace/moa/20020822#"> +					 <saml:AttributeValue> +						<pr:Identification> +						  <pr:Value>K2YMyx3/5kIpNJR+SAD/rbRYH+c=</pr:Value> +						  <pr:Type>urn:publicid:gv.at:wbpk+FN+www.act.at</pr:Type> +						</pr:Identification> +					 </saml:AttributeValue> +				  </saml:Attribute> +				  <saml:Attribute AttributeName="OA" AttributeNamespace="http://reference.e-government.gv.at/namespace/moa/20020822#"> +					 <saml:AttributeValue>https://localhost:48443/mandates/</saml:AttributeValue> +				  </saml:Attribute> +				  <saml:Attribute AttributeName="Geburtsdatum" AttributeNamespace="http://reference.e-government.gv.at/namespace/moa/20020822#"> +					 <saml:AttributeValue>1978-04-29</saml:AttributeValue> +				  </saml:Attribute> +				  <saml:Attribute AttributeName="RepresentationType" AttributeNamespace="http://reference.e-government.gv.at/namespace/mandates/20040701#"> +					 <saml:AttributeValue>Vollmachtsvertreter</saml:AttributeValue> +				  </saml:Attribute> +				  <saml:Attribute AttributeName="MandatorName" AttributeNamespace="http://reference.e-government.gv.at/namespace/mandates/20040701#"> +					 <saml:AttributeValue>MeineTestFirma</saml:AttributeValue> +				  </saml:Attribute> +				  <saml:Attribute AttributeName="MandatorWbpk" AttributeNamespace="http://reference.e-government.gv.at/namespace/mandates/20040701#"> +					 <saml:AttributeValue>123456i</saml:AttributeValue> +				  </saml:Attribute> +				</saml:AttributeStatement> +				<dsig:Signature Id="signature-1216050695-35956125-21395" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> +				  <dsig:SignedInfo> +					 <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> +					 <dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"/> +					 <dsig:Reference Id="signed-data-reference-0-1216050695-35956125-19584" URI=""> +						<dsig:Transforms> +						  <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> +						  <dsig:Transform Algorithm="http://www.w3.org/TR/1999/REC-xslt-19991116"> +							 <xsl:stylesheet version="1.0" xmlns:pr="http://reference.e-government.gv.at/namespace/persondata/20020228#" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +								<xsl:template match="/" xmlns="http://www.w3.org/1999/xhtml"> +								  <html xmlns="http://www.w3.org/1999/xhtml"> +									 <head> +										<title>Signatur der Anmeldedaten</title> +										<style media="screen" type="text/css"> +		  .boldstyle { font-weight: bold; } +		  .italicstyle { font-style: italic; } +		  .annotationstyle { font-size: small; } +		  </style> +									 </head> +									 <body> +										<h1>Signatur der Anmeldedaten</h1> +										<p/> +										<h4>Mit meiner elektronischen Signatur beantrage ich, +			 <span class="boldstyle"> +											 <xsl:value-of select="//@Issuer"/> +										  </span>, geboren am +			 <xsl:value-of select="substring(//saml:Attribute[@AttributeName='Geburtsdatum']/saml:AttributeValue,9,2)"/>. +			 <xsl:value-of select="substring(//saml:Attribute[@AttributeName='Geburtsdatum']/saml:AttributeValue,6,2)"/>. +			 <xsl:value-of select="substring(//saml:Attribute[@AttributeName='Geburtsdatum']/saml:AttributeValue,1,4)"/>, +			 <xsl:if test="//saml:Attribute[@AttributeName='OIDTextualDescription']"> +				in der Rolle als <xsl:value-of select="//saml:Attribute[@AttributeName='OIDTextualDescription']/saml:AttributeValue"/> +				(OID***= <xsl:value-of select="//saml:Attribute[@AttributeName='OID']/saml:AttributeValue"/>), +			 </xsl:if> +			 den Zugang zur gesicherten Anwendung. +		  </h4> +										<p/> +										<h4>Datum und Uhrzeit: +			 <xsl:value-of select="substring(//@IssueInstant,9,2)"/>. +			 <xsl:value-of select="substring(//@IssueInstant,6,2)"/>. +			 <xsl:value-of select="substring(//@IssueInstant,1,4)"/>, +			 <xsl:value-of select="substring(//@IssueInstant,12,2)"/>: +			 <xsl:value-of select="substring(//@IssueInstant,15,2)"/>: +			 <xsl:value-of select="substring(//@IssueInstant,18,2)"/> +										</h4> +										<xsl:if test="//saml:Attribute[@AttributeName='HPI']"> +										  <h4>HPI(**): <xsl:value-of select="//saml:Attribute[@AttributeName='HPI']/saml:AttributeValue"/> +										  </h4> +										</xsl:if> +										<xsl:if test="//saml:Attribute[@AttributeName='wbPK']"> +										  <h4>wbPK(*): <xsl:value-of select="//saml:Attribute[@AttributeName='wbPK']/saml:AttributeValue/pr:Identification/pr:Value"/> +										  </h4> +										</xsl:if> +										<xsl:if test="//saml:Attribute[@AttributeName='MandatorName']"> +										  <hr/> +										  <h4>Ich bin weiters ermächtigt als <xsl:value-of select="//saml:Attribute[@AttributeName='RepresentationType']/saml:AttributeValue/text()"/> +				von <xsl:value-of select="//saml:Attribute[@AttributeName='MandatorName']/saml:AttributeValue/text()"/> +											 <xsl:if test="//saml:Attribute[@AttributeName='MandatorDateOfBirth']">, geboren am +				  <xsl:value-of select="substring(//saml:Attribute[@AttributeName='MandatorDateOfBirth']/saml:AttributeValue,9,2)"/>. +				  <xsl:value-of select="substring(//saml:Attribute[@AttributeName='MandatorDateOfBirth']/saml:AttributeValue,6,2)"/>. +				  <xsl:value-of select="substring(//saml:Attribute[@AttributeName='MandatorDateOfBirth']/saml:AttributeValue,1,4)"/> +											 </xsl:if> +											 <xsl:if test="//saml:Attribute[@AttributeName='MandatorDomainIdentifier']">, +				  <xsl:value-of select="//saml:Attribute[@AttributeName='MandatorDomainIdentifier']/saml:AttributeValue/text()"/> +											 </xsl:if>, in deren Auftrag zu handeln. +			 </h4> +										  <xsl:if test="//saml:Attribute[@AttributeName='MandatorWbpk']"> +											 <h4>wbPK(*) des Vollmachtgebers: <xsl:value-of select="//saml:Attribute[@AttributeName='MandatorWbpk']/saml:AttributeValue/text()"/> +											 </h4> +										  </xsl:if> +										  <p/> +										</xsl:if> +										<xsl:choose> +										  <xsl:when test="//saml:Attribute[@AttributeName='OID']"> +											 <p/> +											 <hr/> +										  </xsl:when> +										  <xsl:when test="//saml:Attribute[@AttributeName='HPI']"> +											 <p/> +											 <hr/> +										  </xsl:when> +										  <xsl:when test="//saml:Attribute[@AttributeName='wbPK']"> +											 <p/> +											 <hr/> +										  </xsl:when> +										</xsl:choose> +										<xsl:if test="//saml:Attribute[@AttributeName='wbPK']"> +										  <div class="annotationstyle">(*) wbPK: Das <span class="italicstyle">wirtschaftsbereichsspezifische Personenkennzeichen</span> wird aus den +			 jeweiligen Stammzahlen des Bürgers und des Wirtschaftsunternehmens berechnet und ermöglicht eine eindeutige Zuordnung des Bürgers zum +			 Wirtschaftsunternehmen.</div> +										</xsl:if> +										<xsl:if test="//saml:Attribute[@AttributeName='HPI']"> +										  <div class="annotationstyle">(**) HPI: Der <span class="italicstyle">eHealth Professional Identifier</span> wird aus den jeweiligen +			 Stammzahlen der Gesundheitsdiensteanbieterinnen / Gesundheitsdiensteanbieter berechnet und ermöglicht eine eindeutige Zuordnung der +			 Gesundheitsdiensteanbieterin / des Gesundheitsdiensteanbieters im Gesundheitsbereich.</div> +										</xsl:if> +										<xsl:if test="//saml:Attribute[@AttributeName='OID']"> +										  <div class="annotationstyle">(***) OID: <span class="italicstyle">Object Identifier</span> sind standardisierte Objekt-Bezeichner und +			 beschreiben eindeutig die Rollen des GDA-Token Inhabers.</div> +										</xsl:if> +									 </body> +								  </html> +								</xsl:template> +							 </xsl:stylesheet> +						  </dsig:Transform> +						  <dsig:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/> +						</dsig:Transforms> +						<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +						<dsig:DigestValue>0q9QWyqAyyiVNNLu1rIcU+nKsEE=</dsig:DigestValue> +					 </dsig:Reference> +					 <dsig:Reference Id="etsi-data-reference-0-1216050695-35956125-7815" Type="http://uri.etsi.org/01903/v1.1.1#SignedProperties" URI="#xmlns(etsi=http://uri.etsi.org/01903/v1.1.1%23)%20xpointer(id('etsi-data-object-0-1216050695-35956125-20638')/child::etsi:QualifyingProperties/child::etsi:SignedProperties)"> +						<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +						<dsig:DigestValue>WtB0/ptvoB/r/7+fauSUIBULymg=</dsig:DigestValue> +					 </dsig:Reference> +				  </dsig:SignedInfo> +				  <dsig:SignatureValue>mZt9DuZiDqG81scsf30qjSDdy6vKC2/n034ZZwMUAvfWOXy3+Ubsk5X5CHhz ++lyI</dsig:SignatureValue> +				  <dsig:KeyInfo> +					 <dsig:X509Data> +						<dsig:X509Certificate>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= +</dsig:X509Certificate> +					 </dsig:X509Data> +				  </dsig:KeyInfo> +				  <dsig:Object Id="etsi-data-object-0-1216050695-35956125-20638"> +					 <etsi:QualifyingProperties Target="#signature-1216050695-35956125-21395" xmlns:etsi="http://uri.etsi.org/01903/v1.1.1#"> +						<etsi:SignedProperties> +						  <etsi:SignedSignatureProperties> +							 <etsi:SigningTime>2008-07-14T15:51:35Z</etsi:SigningTime> +							 <etsi:SigningCertificate> +								<etsi:Cert> +								  <etsi:CertDigest> +									 <etsi:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +									 <etsi:DigestValue>inMYWBmAxMHP7mDENjLFaEtv0Zk=</etsi:DigestValue> +								  </etsi:CertDigest> +								  <etsi:IssuerSerial> +									 <dsig:X509IssuerName>CN=a-sign-Premium-Sig-02,OU=a-sign-Premium-Sig-02,O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH,C=AT</dsig:X509IssuerName> +									 <dsig:X509SerialNumber>132292</dsig:X509SerialNumber> +								  </etsi:IssuerSerial> +								</etsi:Cert> +							 </etsi:SigningCertificate> +							 <etsi:SignaturePolicyIdentifier> +								<etsi:SignaturePolicyImplied/> +							 </etsi:SignaturePolicyIdentifier> +						  </etsi:SignedSignatureProperties> +						  <etsi:SignedDataObjectProperties> +							 <etsi:DataObjectFormat ObjectReference="#signed-data-reference-0-1216050695-35956125-19584"> +								<etsi:MimeType>application/xhtml+xml</etsi:MimeType> +							 </etsi:DataObjectFormat> +						  </etsi:SignedDataObjectProperties> +						</etsi:SignedProperties> +					 </etsi:QualifyingProperties> +				  </dsig:Object> +				</dsig:Signature> +			 </saml:Assertion> +			 <saml:Assertion AssertionID="szr.bmi.gv.at-AssertionID11936526102761952" IssueInstant="2007-10-29T10:10:10+01:00" Issuer="http://portal.bmi.gv.at/ref/szr/issuer" MajorVersion="1" MinorVersion="0" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:ecdsa="http://www.w3.org/2001/04/xmldsig-more#" xmlns:pr="http://reference.e-government.gv.at/namespace/persondata/20020228#" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:si="http://www.w3.org/2001/XMLSchema-instance"> +				<saml:AttributeStatement> +				  <saml:Subject> +					 <saml:SubjectConfirmation> +						<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</saml:ConfirmationMethod> +						<saml:SubjectConfirmationData> +						  <pr:Person si:type="pr:PhysicalPersonType"> +							 <pr:Identification> +								<pr:Value>K2YMyx3/5kIpNJR+SAD/rbRYH+c=</pr:Value> +								<pr:Type>urn:publicid:gv.at:wbpk+FN+www.act.at</pr:Type> +							 </pr:Identification> +							 <pr:Name> +								<pr:GivenName>Thomas</pr:GivenName> +								<pr:FamilyName primary="undefined">Knall</pr:FamilyName> +							 </pr:Name> +							 <pr:DateOfBirth>1978-04-29</pr:DateOfBirth> +						  </pr:Person> +						</saml:SubjectConfirmationData> +					 </saml:SubjectConfirmation> +				  </saml:Subject> +				  <saml:Attribute AttributeName="CitizenPublicKey" AttributeNamespace="urn:publicid:gv.at:namespaces:identitylink:1.2"> +					 <saml:AttributeValue> +						<ecdsa:ECDSAKeyValue> +						  <ecdsa:DomainParameters> +							 <ecdsa:NamedCurve URN="urn:oid:1.2.840.10045.3.1.1"/> +						  </ecdsa:DomainParameters> +						  <ecdsa:PublicKey> +							 <ecdsa:X Value="2638720011055700682018137297354399374048880611104468142324" si:type="ecdsa:PrimeFieldElemType"/> +							 <ecdsa:Y Value="2804889174475641803405778188053052844820705830770276369958" si:type="ecdsa:PrimeFieldElemType"/> +						  </ecdsa:PublicKey> +						</ecdsa:ECDSAKeyValue> +					 </saml:AttributeValue> +				  </saml:Attribute> +				  <saml:Attribute AttributeName="CitizenPublicKey" AttributeNamespace="urn:publicid:gv.at:namespaces:identitylink:1.2"> +					 <saml:AttributeValue> +						<dsig:RSAKeyValue> +						  <dsig:Modulus>sWOqPZzPTn9VvBR5LjuopIWYdh5aGzuX2vMjofhn8bStba1CDW1qkDdlYW4Rs/DfU/I1uqor4Lje +/G3Yzh82yD0MHdzlW8MYUJ8RJe+czbjRUPaSbC/NRqhyF3eKnflxM++sJb2abrUH/9TV0q8P5QRS +uZC/JpAEYpSazysPz/fv8AEnU8oxcTvCiax1jf2GZPmm3qFjPc4qDYNHqfnE8yWYt7kHeqPV/cRw +x3aMGW8mRwQZb7VRFLW5g37nrt9N</dsig:Modulus> +						  <dsig:Exponent>AQAB</dsig:Exponent> +						</dsig:RSAKeyValue> +					 </saml:AttributeValue> +				  </saml:Attribute> +				</saml:AttributeStatement> +				<dsig:Signature> +				  <dsig:SignedInfo> +					 <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> +					 <dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> +					 <dsig:Reference URI=""> +						<dsig:Transforms> +						  <dsig:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> +							 <dsig:XPath>not(ancestor-or-self::pr:Identification)</dsig:XPath> +						  </dsig:Transform> +						  <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> +						</dsig:Transforms> +						<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +						<dsig:DigestValue>b3d/wcQb0Bl0/6GSPsrMxWpdRLA=</dsig:DigestValue> +					 </dsig:Reference> +					 <dsig:Reference Type="http://www.w3.org/2000/09/xmldsig#Manifest" URI="#manifest"> +						<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +						<dsig:DigestValue>eet0q3Thmw6+cbO1fazbEg0556I=</dsig:DigestValue> +					 </dsig:Reference> +				  </dsig:SignedInfo> +				  <dsig:SignatureValue> +oy55Cq7IyYy7z/TO2a3+m7tjG/ztiKhxhGzVqEYIWIObEOs/GVJDCCI4oe/HS8Fhc4TaXDcZXk4y +qBp4JJ288TeaNjPYkPzp38nWJ4xRatEyo7VaySXy+TqgwiBT5uhxrwkroCr4ZIWwOvt1uR5UBVAf +qk1ii+LPW2WYE3bMpoHfrM9CdFSPzWTRl/0zsEURc64EBPyIdKz+c70DaexeX2E0JVelKcj+jDaJ +mHsFhi/9QoscqPEVA87qv07yhyK5S41+f3HDvpuhYwvQDdOq50sclfsI+g9r473VxiRsOmJ9Ak4/ +k2KP0tgfAQ+h5hRGQUUo5LYPywjg7zPxe8SGGA== +</dsig:SignatureValue> +				  <dsig:KeyInfo> +					 <dsig:X509Data> +						<dsig:X509Certificate> +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= +</dsig:X509Certificate> +					 </dsig:X509Data> +				  </dsig:KeyInfo> +				  <dsig:Object> +					 <dsig:Manifest Id="manifest"> +						<dsig:Reference URI=""> +						  <dsig:Transforms> +							 <dsig:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> +								<dsig:XPath>not(ancestor-or-self::dsig:Signature)</dsig:XPath> +							 </dsig:Transform> +						  </dsig:Transforms> +						  <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +						  <dsig:DigestValue>JZGwiDzQAtJtnJMeeXyypTrDjwY=</dsig:DigestValue> +						</dsig:Reference> +					 </dsig:Manifest> +				  </dsig:Object> +				</dsig:Signature> +			 </saml:Assertion> +		  </saml:SubjectConfirmationData> +		</saml:SubjectConfirmation> +	 </saml:Subject> +	 <saml:Attribute AttributeName="PersonData" AttributeNamespace="http://reference.e-government.gv.at/namespace/persondata/20020228#"> +		<saml:AttributeValue> +		  <pr:Person si:type="pr:PhysicalPersonType" xmlns:pr="http://reference.e-government.gv.at/namespace/persondata/20020228#" xmlns:si="http://www.w3.org/2001/XMLSchema-instance"> +			 <pr:Identification> +				<pr:Value>K2YMyx3/5kIpNJR+SAD/rbRYH+c=</pr:Value> +				<pr:Type>urn:publicid:gv.at:wbpk+FN+www.act.at</pr:Type> +			 </pr:Identification> +			 <pr:Name> +				<pr:GivenName>Thomas</pr:GivenName> +				<pr:FamilyName primary="undefined">Knall</pr:FamilyName> +			 </pr:Name> +			 <pr:DateOfBirth>1978-04-29</pr:DateOfBirth> +		  </pr:Person> +		</saml:AttributeValue> +	 </saml:Attribute> +	 <saml:Attribute AttributeName="isQualifiedCertificate" AttributeNamespace="http://reference.e-government.gv.at/namespace/moa/20020822#"> +		<saml:AttributeValue>true</saml:AttributeValue> +	 </saml:Attribute> +	 <saml:Attribute AttributeName="bkuURL" AttributeNamespace="http://reference.e-government.gv.at/namespace/moa/20020822#"> +		<saml:AttributeValue>https://127.0.0.1:3496/https-security-layer-request</saml:AttributeValue> +	 </saml:Attribute> +	 <saml:Attribute AttributeName="SignerCertificate" AttributeNamespace="http://reference.e-government.gv.at/namespace/moa/20020822#"> +		<saml:AttributeValue>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=</saml:AttributeValue> +	 </saml:Attribute> +	 <saml:Attribute AttributeName="Mandate" AttributeNamespace="http://reference.e-government.gv.at/namespace/mandates/20040701#"> +		<saml:AttributeValue> +		  <md:Mandate MandateID="https://egov.act.at/mandates/20080714174835/886164" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:md="http://reference.e-government.gv.at/namespace/mandates/20040701#" xmlns:pr="http://reference.e-government.gv.at/namespace/persondata/20020228#"> +			 <md:Annotation>Prokura - MeineTestFirma</md:Annotation> +			 <md:StatusInformationService>http://localhost:58080/omsp/OMSPRequest</md:StatusInformationService> +			 <md:Representative> +				<pr:PhysicalPerson> +				  <pr:Identification> +					 <pr:Value>K2YMyx3/5kIpNJR+SAD/rbRYH+c=</pr:Value> +					 <pr:Type>urn:publicid:gv.at:wbpk+FN+www.act.at</pr:Type> +				  </pr:Identification> +				  <pr:Name> +					 <pr:GivenName>Thomas</pr:GivenName> +					 <pr:FamilyName primary="undefined">Knall</pr:FamilyName> +				  </pr:Name> +				  <pr:DateOfBirth>1978-04-29</pr:DateOfBirth> +				</pr:PhysicalPerson> +			 </md:Representative> +			 <md:Mandator> +				<pr:CorporateBody> +				  <pr:Identification> +					 <pr:Value>123456i</pr:Value> +					 <pr:Type>urn:publicid:gv.at:baseid+XFN</pr:Type> +				  </pr:Identification> +				  <pr:FullName>MeineTestFirma</pr:FullName> +				</pr:CorporateBody> +			 </md:Mandator> +			 <md:Issued> +				<md:Place>Wien</md:Place> +				<md:Date>2008-07-14</md:Date> +			 </md:Issued> +			 <md:Properties> +				<md:SubstitutionAllowed>false</md:SubstitutionAllowed> +			 </md:Properties> +			 <md:SimpleMandateContent> +				<md:TextualDescription>Der/Die Bevollmächtigte wird zum Prokuristen/Prokuristin bestellt.</md:TextualDescription> +			 </md:SimpleMandateContent> +			 <dsig:Signature Id="signature-1-1" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> +				<dsig:SignedInfo> +				  <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> +				  <dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"/> +				  <dsig:Reference Id="reference-1-1" URI=""> +					 <dsig:Transforms> +						<dsig:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> +						  <dsig:XPath xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:moa="http://reference.e-government.gv.at/namespace/moa/20020822#" xmlns:pr="http://reference.e-government.gv.at/namespace/persondata/20020228#">not(ancestor-or-self::pr:Identification or ancestor-or-self::dsig:Signature)</dsig:XPath> +						</dsig:Transform> +						<dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> +						<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> +					 </dsig:Transforms> +					 <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +					 <dsig:DigestValue>PRRF0sWBgoywztCKWEXafZfhpd0=</dsig:DigestValue> +				  </dsig:Reference> +				  <dsig:Reference Type="http://www.w3.org/2000/09/xmldsig#Manifest" URI="#dsig-manifest-1-1"> +					 <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +					 <dsig:DigestValue>NorNorUqPFMA06JfxSJopOq7Qv0=</dsig:DigestValue> +				  </dsig:Reference> +				</dsig:SignedInfo> +				<dsig:SignatureValue>IQMZFc57XZd9LjeiaZqSfzZtWuXhuikAqbKA7pWuDK02DLFSYZPXsGjcvnwNdVaP</dsig:SignatureValue> +				<dsig:KeyInfo> +				  <dsig:X509Data> +					 <dsig:X509Certificate>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=</dsig:X509Certificate> +				  </dsig:X509Data> +				</dsig:KeyInfo> +				<dsig:Object> +				  <dsig:Manifest Id="dsig-manifest-1-1"> +					 <dsig:Reference Id="reference-1-2" URI=""> +						<dsig:Transforms> +						  <dsig:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> +							 <dsig:XPath xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:moa="http://reference.e-government.gv.at/namespace/moa/20020822#" xmlns:pr="http://reference.e-government.gv.at/namespace/persondata/20020228#">not(ancestor-or-self::dsig:Signature)</dsig:XPath> +						  </dsig:Transform> +						  <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> +						  <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> +						</dsig:Transforms> +						<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +						<dsig:DigestValue>oz6ThHPL3V7RNibfPrDSWVhUgi8=</dsig:DigestValue> +					 </dsig:Reference> +				  </dsig:Manifest> +				</dsig:Object> +			 </dsig:Signature> +		  </md:Mandate> +		</saml:AttributeValue> +	 </saml:Attribute> +  </saml:AttributeStatement> +</saml:Assertion> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<dsig:Signature Id="signature-1216050695-35956125-21395" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> +  <dsig:SignedInfo> +	 <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> +	 <dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"/> +	 <dsig:Reference Id="signed-data-reference-0-1216050695-35956125-19584" URI=""> +		<dsig:Transforms> +		  <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> +		  <dsig:Transform Algorithm="http://www.w3.org/TR/1999/REC-xslt-19991116"> +			 <xsl:stylesheet version="1.0" xmlns:pr="http://reference.e-government.gv.at/namespace/persondata/20020228#" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +				<xsl:template match="/" xmlns="http://www.w3.org/1999/xhtml"> +				  <html xmlns="http://www.w3.org/1999/xhtml"> +					 <head> +						<title>Signatur der Anmeldedaten</title> +						<style media="screen" type="text/css"> +.boldstyle { font-weight: bold; } +.italicstyle { font-style: italic; } +.annotationstyle { font-size: small; } +</style> +					 </head> +					 <body> +						<h1>Signatur der Anmeldedaten</h1> +						<p/> +						<h4>Mit meiner elektronischen Signatur beantrage ich, +<span class="boldstyle"> +							 <xsl:value-of select="//@Issuer"/> +						  </span>, geboren am +<xsl:value-of select="substring(//saml:Attribute[@AttributeName='Geburtsdatum']/saml:AttributeValue,9,2)"/>. +<xsl:value-of select="substring(//saml:Attribute[@AttributeName='Geburtsdatum']/saml:AttributeValue,6,2)"/>. +<xsl:value-of select="substring(//saml:Attribute[@AttributeName='Geburtsdatum']/saml:AttributeValue,1,4)"/>, +<xsl:if test="//saml:Attribute[@AttributeName='OIDTextualDescription']"> +in der Rolle als <xsl:value-of select="//saml:Attribute[@AttributeName='OIDTextualDescription']/saml:AttributeValue"/> +(OID***= <xsl:value-of select="//saml:Attribute[@AttributeName='OID']/saml:AttributeValue"/>), +</xsl:if> +den Zugang zur gesicherten Anwendung. +</h4> +						<p/> +						<h4>Datum und Uhrzeit: +<xsl:value-of select="substring(//@IssueInstant,9,2)"/>. +<xsl:value-of select="substring(//@IssueInstant,6,2)"/>. +<xsl:value-of select="substring(//@IssueInstant,1,4)"/>, +<xsl:value-of select="substring(//@IssueInstant,12,2)"/>: +<xsl:value-of select="substring(//@IssueInstant,15,2)"/>: +<xsl:value-of select="substring(//@IssueInstant,18,2)"/> +						</h4> +						<xsl:if test="//saml:Attribute[@AttributeName='HPI']"> +						  <h4>HPI(**): <xsl:value-of select="//saml:Attribute[@AttributeName='HPI']/saml:AttributeValue"/> +						  </h4> +						</xsl:if> +						<xsl:if test="//saml:Attribute[@AttributeName='wbPK']"> +						  <h4>wbPK(*): <xsl:value-of select="//saml:Attribute[@AttributeName='wbPK']/saml:AttributeValue/pr:Identification/pr:Value"/> +						  </h4> +						</xsl:if> +						<xsl:if test="//saml:Attribute[@AttributeName='MandatorName']"> +						  <hr/> +						  <h4>Ich bin weiters ermächtigt als <xsl:value-of select="//saml:Attribute[@AttributeName='RepresentationType']/saml:AttributeValue/text()"/> +von <xsl:value-of select="//saml:Attribute[@AttributeName='MandatorName']/saml:AttributeValue/text()"/> +							 <xsl:if test="//saml:Attribute[@AttributeName='MandatorDateOfBirth']">, geboren am +  <xsl:value-of select="substring(//saml:Attribute[@AttributeName='MandatorDateOfBirth']/saml:AttributeValue,9,2)"/>. +  <xsl:value-of select="substring(//saml:Attribute[@AttributeName='MandatorDateOfBirth']/saml:AttributeValue,6,2)"/>. +  <xsl:value-of select="substring(//saml:Attribute[@AttributeName='MandatorDateOfBirth']/saml:AttributeValue,1,4)"/> +							 </xsl:if> +							 <xsl:if test="//saml:Attribute[@AttributeName='MandatorDomainIdentifier']">, +  <xsl:value-of select="//saml:Attribute[@AttributeName='MandatorDomainIdentifier']/saml:AttributeValue/text()"/> +							 </xsl:if>, in deren Auftrag zu handeln. +</h4> +						  <xsl:if test="//saml:Attribute[@AttributeName='MandatorWbpk']"> +							 <h4>wbPK(*) des Vollmachtgebers: <xsl:value-of select="//saml:Attribute[@AttributeName='MandatorWbpk']/saml:AttributeValue/text()"/> +							 </h4> +						  </xsl:if> +						  <p/> +						</xsl:if> +						<xsl:choose> +						  <xsl:when test="//saml:Attribute[@AttributeName='OID']"> +							 <p/> +							 <hr/> +						  </xsl:when> +						  <xsl:when test="//saml:Attribute[@AttributeName='HPI']"> +							 <p/> +							 <hr/> +						  </xsl:when> +						  <xsl:when test="//saml:Attribute[@AttributeName='wbPK']"> +							 <p/> +							 <hr/> +						  </xsl:when> +						</xsl:choose> +						<xsl:if test="//saml:Attribute[@AttributeName='wbPK']"> +						  <div class="annotationstyle">(*) wbPK: Das <span class="italicstyle">wirtschaftsbereichsspezifische Personenkennzeichen</span> wird aus den +jeweiligen Stammzahlen des Bürgers und des Wirtschaftsunternehmens berechnet und ermöglicht eine eindeutige Zuordnung des Bürgers zum +Wirtschaftsunternehmen.</div> +						</xsl:if> +						<xsl:if test="//saml:Attribute[@AttributeName='HPI']"> +						  <div class="annotationstyle">(**) HPI: Der <span class="italicstyle">eHealth Professional Identifier</span> wird aus den jeweiligen +Stammzahlen der Gesundheitsdiensteanbieterinnen / Gesundheitsdiensteanbieter berechnet und ermöglicht eine eindeutige Zuordnung der +Gesundheitsdiensteanbieterin / des Gesundheitsdiensteanbieters im Gesundheitsbereich.</div> +						</xsl:if> +						<xsl:if test="//saml:Attribute[@AttributeName='OID']"> +						  <div class="annotationstyle">(***) OID: <span class="italicstyle">Object Identifier</span> sind standardisierte Objekt-Bezeichner und +beschreiben eindeutig die Rollen des GDA-Token Inhabers.</div> +						</xsl:if> +					 </body> +				  </html> +				</xsl:template> +			 </xsl:stylesheet> +		  </dsig:Transform> +		  <dsig:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/> +		</dsig:Transforms> +		<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +		<dsig:DigestValue>0q9QWyqAyyiVNNLu1rIcU+nKsEE=</dsig:DigestValue> +	 </dsig:Reference> +	 <dsig:Reference Id="etsi-data-reference-0-1216050695-35956125-7815" Type="http://uri.etsi.org/01903/v1.1.1#SignedProperties" URI="#xmlns(etsi=http://uri.etsi.org/01903/v1.1.1%23)%20xpointer(id('etsi-data-object-0-1216050695-35956125-20638')/child::etsi:QualifyingProperties/child::etsi:SignedProperties)"> +		<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +		<dsig:DigestValue>WtB0/ptvoB/r/7+fauSUIBULymg=</dsig:DigestValue> +	 </dsig:Reference> +  </dsig:SignedInfo> +  <dsig:SignatureValue>mZt9DuZiDqG81scsf30qjSDdy6vKC2/n034ZZwMUAvfWOXy3+Ubsk5X5CHhz ++lyI</dsig:SignatureValue> +  <dsig:KeyInfo> +	 <dsig:X509Data> +		<dsig:X509Certificate>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= +</dsig:X509Certificate> +	 </dsig:X509Data> +  </dsig:KeyInfo> +  <dsig:Object Id="etsi-data-object-0-1216050695-35956125-20638"> +	 <etsi:QualifyingProperties Target="#signature-1216050695-35956125-21395" xmlns:etsi="http://uri.etsi.org/01903/v1.1.1#"> +		<etsi:SignedProperties> +		  <etsi:SignedSignatureProperties> +			 <etsi:SigningTime>2008-07-14T15:51:35Z</etsi:SigningTime> +			 <etsi:SigningCertificate> +				<etsi:Cert> +				  <etsi:CertDigest> +					 <etsi:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> +					 <etsi:DigestValue>inMYWBmAxMHP7mDENjLFaEtv0Zk=</etsi:DigestValue> +				  </etsi:CertDigest> +				  <etsi:IssuerSerial> +					 <dsig:X509IssuerName>CN=a-sign-Premium-Sig-02,OU=a-sign-Premium-Sig-02,O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH,C=AT</dsig:X509IssuerName> +					 <dsig:X509SerialNumber>132292</dsig:X509SerialNumber> +				  </etsi:IssuerSerial> +				</etsi:Cert> +			 </etsi:SigningCertificate> +			 <etsi:SignaturePolicyIdentifier> +				<etsi:SignaturePolicyImplied/> +			 </etsi:SignaturePolicyIdentifier> +		  </etsi:SignedSignatureProperties> +		  <etsi:SignedDataObjectProperties> +			 <etsi:DataObjectFormat ObjectReference="#signed-data-reference-0-1216050695-35956125-19584"> +				<etsi:MimeType>application/xhtml+xml</etsi:MimeType> +			 </etsi:DataObjectFormat> +		  </etsi:SignedDataObjectProperties> +		</etsi:SignedProperties> +	 </etsi:QualifyingProperties> +  </dsig:Object> +</dsig:Signature>
\ No newline at end of file | 
