summaryrefslogtreecommitdiff
path: root/eaaf_core/src/main/java/at/gv/egiz
diff options
context:
space:
mode:
Diffstat (limited to 'eaaf_core/src/main/java/at/gv/egiz')
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IDestroyableObject.java16
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IGarbageCollectorProcessing.java16
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IPostStartupInitializable.java21
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequest.java234
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequestStorage.java40
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IStatusMessager.java49
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/EAAFConfigConstants.java8
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/EAAFConstants.java42
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/ExceptionContainer.java74
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/ILoALevelMapper.java22
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/PVPAttributeDefinitions.java251
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/XMLNamespaceConstants.java474
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIBuilderConfiguration.java54
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIBuilderConfigurationFactory.java30
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIFormBuilder.java70
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/ModifyableGuiBuilderConfiguration.java25
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/EAAFAuthProcessDataConstants.java21
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAction.java43
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAttributeBuilder.java32
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAttributeGenerator.java39
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAuthData.java198
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAuthenticationDataBuilder.java14
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IConfiguration.java108
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IModulInfo.java75
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IPVPAttributeBuilder.java9
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/ISPConfiguration.java131
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/IAuthenticationManager.java72
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/ISSOManager.java92
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/data/IAuthProcessDataContainer.java144
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/data/IIdentityLink.java155
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/modules/AuthModule.java44
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExecutionContext.java65
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExpressionEvaluationContext.java25
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExpressionEvaluator.java27
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ProcessEngine.java114
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ProcessInstanceStoreDAO.java47
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/Task.java28
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/slo/ISLOInformationContainer.java68
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/slo/SLOInformationInterface.java80
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/logging/IRevisionLogger.java38
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/logging/IStatisticLogger.java20
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/storage/ITransactionStorage.java114
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AttributeBuilderException.java13
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AttributePolicyException.java20
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AuthnRequestValidatorException.java49
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFAuthenticationException.java21
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFBuilderException.java20
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFConfigurationException.java20
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFException.java45
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFIDPException.java17
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFIllegalStateException.java15
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFParserException.java20
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFProtocolException.java26
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFSSOException.java17
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFStorageException.java18
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/GUIBuildException.java26
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/InvalidDateFormatAttributeException.java15
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/InvalidProtocolRequestException.java23
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/NoPassivAuthenticationException.java18
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/ProcessExecutionException.java38
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/ProtocolNotActiveException.java20
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/SLOException.java21
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/TaskExecutionException.java55
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/UnavailableAttributeException.java22
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/XPathException.java68
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/Pair.java25
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/SLOInformationImpl.java167
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/Trible.java31
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGUIFormBuilderConfiguration.java90
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGUIFormBuilderImpl.java192
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/velocity/VelocityLogAdapter.java81
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/velocity/VelocityProvider.java121
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/AuthenticationData.java416
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/EAAFCoreSpringResourceProvider.java30
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/AbstractAuthenticationManager.java341
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java119
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/AbstractAuthenticationDataBuilder.java467
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/BPKBuilder.java302
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/AuthProcessDataWrapper.java219
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/IdentityLink.java312
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/SimpleIdentityLinkAssertionParser.java326
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/AbstractAuthServletTask.java220
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/ModuleRegistration.java151
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BPKAttributeBuilder.java55
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BirthdateAttributeBuilder.java40
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDIdentityLinkBuilder.java54
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDIssuingNationAttributeBuilder.java35
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSectorForIDAttributeBuilder.java36
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSourcePIN.java39
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSourcePINType.java33
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDeIDASQAALevelAttributeBuilder.java31
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/GivenNameAttributeBuilder.java26
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/PVPVersionAttributeBuilder.java26
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/PrincipalNameAttributeBuilder.java26
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/AbstractConfigurationImpl.java185
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/SPConfigurationImpl.java163
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractAuthProtocolModulController.java225
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java354
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java97
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java178
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/protocols/RequestImpl.java386
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/FinalizeAuthenticationTask.java57
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/RestartAuthProzessManagement.java92
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExecutionContextImpl.java81
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExpressionEvaluationContextImpl.java46
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java226
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParserException.java37
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java424
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstance.java166
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstanceState.java32
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStore.java75
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDAOImpl.java73
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/EndEvent.java44
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessDefinition.java160
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessNode.java71
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/StartEvent.java47
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/TaskInfo.java96
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/Transition.java138
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/spring/SpringExpressionEvaluator.java63
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractAuthSourceServlet.java118
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractTask.java101
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/SpringWebExpressionEvaluator.java145
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/support/SecureRandomHolder.java37
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/logging/DummyRevisionsLogger.java52
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/logging/DummyStatisticLogger.java43
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java1243
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java113
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java104
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java142
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java178
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java175
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java319
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java89
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java46
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java205
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java69
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java177
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java85
-rw-r--r--eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java523
139 files changed, 15327 insertions, 0 deletions
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IDestroyableObject.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IDestroyableObject.java
new file mode 100644
index 00000000..52979cd2
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IDestroyableObject.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface IDestroyableObject {
+ /**
+ * Manually deep destroy a Java object with all child objects like timers and threads
+ *
+ */
+ public void fullyDestroy();
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IGarbageCollectorProcessing.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IGarbageCollectorProcessing.java
new file mode 100644
index 00000000..7b153b2e
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IGarbageCollectorProcessing.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface IGarbageCollectorProcessing {
+
+ /**
+ * This method gets executed by the MOA garbage collector at regular intervals.
+ *
+ */
+ public void runGarbageCollector();
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IPostStartupInitializable.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IPostStartupInitializable.java
new file mode 100644
index 00000000..f2fae3af
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IPostStartupInitializable.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api;
+
+
+/**
+ *
+ * @author tlenz
+ *
+ * Interface initialize a Object when the MOA-ID-Auth start-up process is fully completed
+ *
+ */
+public interface IPostStartupInitializable {
+
+ /**
+ * This method is called once when MOA-ID-Auth start-up process is fully completed
+ *
+ */
+ public void executeAfterStartup();
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequest.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequest.java
new file mode 100644
index 00000000..02070ee1
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequest.java
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ *******************************************************************************/
+/*******************************************************************************
+*
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api;
+
+import java.util.Map;
+
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException;
+
+public interface IRequest {
+
+ /**
+ * Indicates the module, which implements this authentication protocol.
+ * The class, which is referenced, had to implement the 'IModulInfo' interface.
+ *
+ * @return Full-qualified name of the class which implements this protocol
+ */
+ public String requestedModule();
+
+ /**
+ * Indicates the protocol specific action, which should executed if the request is processed.
+ * The class, which is referenced, had to implement the 'IAction' interface.
+ *
+ * @return Full-qualified name of the class which implements the action
+ */
+ public String requestedAction();
+
+ /**
+ * Unique identifier, which indicates the service provider.
+ *
+ * @return Unique identifier for the service provider
+ */
+ public String getSPEntityId();
+
+ /**
+ * Indicates the passive flag in authentication requests.
+ * If the passive flag is set, the identification and authentication process
+ * failed if no active SSO session is found.
+ *
+ * @return true, if the is passive flag is set in authentication request, otherwise false
+ */
+ public boolean isPassiv();
+
+ /**
+ * Indicates the force authentication flag in authentication request
+ * If this flag is set, a new identification and authentication process
+ * is carried out in any case.
+ *
+ * @return true, if the force authentication flag is set, otherwise false
+ */
+ public boolean forceAuth();
+
+
+ /**
+ * Returns a generic request-data object with is stored with a specific identifier
+ *
+ * @param key The specific identifier of the request-data object
+ * @return The request-data object or null if no data is found with this key
+ */
+ public Object getGenericData(String key);
+
+ /**
+ * Returns a generic request-data object with is stored with a specific identifier
+ *
+ * @param key The specific identifier of the request-data object
+ * @param clazz The class type which is stored with this key
+ * @return The request-data object or null if no data is found with this key
+ */
+ public <T> T getGenericData(String key, final Class<T> clazz);
+
+ /**
+ * Store a generic data-object into pending request with a specific identifier
+ *
+ * @param key Identifier for this data-object
+ * @param object Generic data-object which should be stored. This data-object had to be implement the 'java.io.Serializable' interface
+ * @throws SessionDataStorageException Error message if the data-object can not stored to generic request-data storage
+ */
+ public void setGenericDataToSession(String key, Object object) throws EAAFStorageException;
+
+ /**
+ * Store generic data-objects into pending request with specific identifiers
+ *
+ * @param map Map with Identifiers and values
+ * @throws SessionDataStorageException Error message if the data-object can not stored to generic request-data storage
+ */
+ public void setGenericDataToSession(Map<String, Object> map) throws EAAFStorageException;
+
+
+
+ /**
+ * Get the internal dataStorage map
+ *
+ * @return read-only map of data stored to this pending request
+ */
+ public Map<String, Object> genericFullDataStorage();
+
+ /**
+ * Hold the identifier of this request object.
+ * This identifier can be used to load the request from request storage
+ *
+ * @return Request identifier
+ */
+ public String getPendingRequestId();
+
+
+ /**
+ * Hold the identifier of the SSO-Session which is associated with this request
+ *
+ * @return SSO session-identifier if a associated session exists, otherwise null
+ */
+ public String getSSOSessionIdentifier();
+
+ /**
+ * Set the in SSO session identifier, if an active SSO session exists
+ *
+ * @param internalSSOSessionId
+ */
+ public void setSSOSessionIdentifier(String internalSSOSessionId);
+
+ /**
+ * Holds a unique transaction identifier, which could be used for looging
+ * This transaction identifier is unique for a single identification and authentication process
+ *
+ * @return Unique transaction identifier.
+ */
+ public String getUniqueTransactionIdentifier();
+
+ /**
+ * Holds a unique session identifier, which could be used for logging
+ * This session identifier is unique for the full Single Sign-On session time
+ *
+ * @return Unique session identifier
+ */
+ public String getUniqueSessionIdentifier();
+
+
+ /**
+ * Hold the identifier if the process instance, which is associated with this request
+ *
+ * @return ProcessInstanceID if this request is associated with a authentication process, otherwise null
+ */
+ public String getProcessInstanceId();
+
+
+ /**
+ * get the IDP URL PreFix, which was used for authentication request
+ *
+ * @return IDP URL PreFix <String>. The URL prefix always ends without /
+ */
+ public String getAuthURL();
+ public String getAuthURLWithOutSlash();
+
+ /**
+ * Indicates if this pending request needs authentication
+ *
+ * @return true if this request needs authentication, otherwise false
+ */
+ public boolean isNeedAuthentication();
+
+ /**
+ * Indicates, if this pending request needs Single Sign-On (SSO) functionality
+ *
+ * @return true if this request needs SSO, otherwise false
+ */
+ public boolean needSingleSignOnFunctionality();
+ public void setNeedSingleSignOnFunctionality(boolean needSSO);
+
+
+ /**
+ * Indicates, if this pending request needs an additional user consent
+ *
+ * @return true if this request needs additional user consent, otherwise false
+ */
+ public boolean isNeedUserConsent();
+ public void setNeedUserConsent(boolean needConsent);
+
+ /**
+ * Indicates, if this pending request is already authenticated
+ *
+ * @return true if this request is already authenticated, otherwise false
+ */
+ public boolean isAuthenticated();
+ public void setAuthenticated(boolean isAuthenticated);
+
+ /**
+ * Get get Service-Provider configuration which is associated with this request.
+ *
+ * @return Service-Provider configuration
+ */
+ public ISPConfiguration getServiceProviderConfiguration();
+
+
+ /**
+ * Get get Service-Provider configuration which is associated with this request.
+ *
+ * @return Service-Provider configuration as object
+ */
+ public <T> T getServiceProviderConfiguration(final Class<T> decorator);
+
+
+ /**
+ * Indicates, if this pending-request is aborted by the user
+ *
+ * @return true, if it is aborted, otherwise false
+ */
+ public boolean isAbortedByUser();
+
+ /**
+ * Set the 'isAboredByUser' flag of this pending-request
+ *
+ * @param b true, if the user has abort the authentication process, otherwise false
+ */
+ public void setAbortedByUser(boolean isAborted);
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequestStorage.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequestStorage.java
new file mode 100644
index 00000000..ce526fa8
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IRequestStorage.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ *******************************************************************************/
+/*
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egiz.eaaf.core.api;
+
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface IRequestStorage {
+
+ public IRequest getPendingRequest(String pendingReqID);
+
+ public void storePendingRequest(IRequest pendingRequest) throws EAAFException;
+
+ public void removePendingRequest(String requestID);
+
+ public String changePendingRequestID(IRequest pendingRequest) throws EAAFException;
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IStatusMessager.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IStatusMessager.java
new file mode 100644
index 00000000..40d86352
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/IStatusMessager.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api;
+
+public interface IStatusMessager {
+
+ //internal error codes defined in EAAFCore
+ public static final String CODES_INTERNAL_ERROR_GENERIC = "internal.00";
+ public static final String CODES_INTERNAL_ERROR_AUTH_NOSPCONFIG = "auth.00";
+ public static final String CODES_INTERNAL_ERROR_AUTH_NOPENDIGREQID = "auth.26";
+ public static final String CODES_INTERNAL_ERROR_AUTH_TIMEOUT = "auth.28";
+ public static final String CODES_INTERNAL_ERROR_AUTH_USERSTOP = "auth.21";
+ public static final String CODES_INTERNAL_ERROR_AUTH_REQUEST_INVALID = "auth.35";
+
+ public static final String CODES_INTERNAL_ILLEGAL_STATE = "process.03";
+
+ //external error codes defined in EAAFCore
+ public static final String CODES_EXTERNAL_ERROR_GENERIC = "9199";
+ public static final String CODES_EXTERNAL_ERROR_PROCESSENGINE = "1100";
+
+
+ /**
+ * Get the message corresponding to a given message ID.
+ *
+ * @param messageId The ID of the message.
+ * @param parameters The parameters to fill in into the message arguments.
+ * @return The formatted message.
+ */
+ public String getMessage(String messageId, Object[] parameters);
+
+
+ /**
+ * Get external errorCode from from Exception
+ *
+ * @param throwable
+ * @return
+ */
+ public String getResponseErrorCode(Throwable throwable);
+
+
+ /**
+ * Map internal to external errorCode
+ *
+ * @param intErrorCode
+ * @return
+ */
+ public String mapInternalErrorToExternalError(String intErrorCode);
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/EAAFConfigConstants.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/EAAFConfigConstants.java
new file mode 100644
index 00000000..4f35a681
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/EAAFConfigConstants.java
@@ -0,0 +1,8 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.data;
+
+public class EAAFConfigConstants {
+
+ public static final String SERVICE_UNIQUEIDENTIFIER = "uniqueID"; //publicURLPrefix
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/EAAFConstants.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/EAAFConstants.java
new file mode 100644
index 00000000..c9d1263a
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/EAAFConstants.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.data;
+
+
+public class EAAFConstants {
+
+ public static final String CONTENTTYPE_HTML_UTF8 = "text/html; charset=UTF-8";
+
+ //http request parameters for process management
+ public static final String PARAM_HTTP_TARGET_PENDINGREQUESTID = "pendingid";
+ public static final String PARAM_HTTP_ERROR_CODE = "errorid";
+
+
+ public static final String EIDAS_QAA_PREFIX = "http://eidas.europa.eu/LoA/";
+ public static final String EIDAS_QAA_LOW = EIDAS_QAA_PREFIX + "low";
+ public static final String EIDAS_QAA_SUBSTANTIAL = EIDAS_QAA_PREFIX + "substantial";
+ public static final String EIDAS_QAA_HIGH = EIDAS_QAA_PREFIX + "high";
+
+
+ //Austrian specific prefixes for pseudonyms of users
+ public static final String URN_PREFIX = "urn:publicid:gv.at";
+ public static final String URN_PREFIX_BASEID = URN_PREFIX + ":baseid";
+ public static final String URN_PREFIX_CDID = URN_PREFIX + ":cdid+";
+ public static final String URN_PREFIX_BPK = URN_PREFIX_CDID + "bpk";
+ public static final String URN_PREFIX_WBPK = URN_PREFIX + ":wbpk+";
+ public static final String URN_PREFIX_EIDAS = URN_PREFIX + ":eidasid+";
+
+ //Authentication process data_constants
+ public static final String UNIQUESESSIONIDENTIFIER = "eaaf_uniqueSessionIdentifier";
+ public static final String AUTH_DATA_CREATED = "eaaf_authdata_created";
+
+
+ public static final String PROCESS_ENGINE_PREFIX = "PARAMS_";
+ public static final String PROCESS_ENGINE_PENDINGREQUESTID = PROCESS_ENGINE_PREFIX + PARAM_HTTP_TARGET_PENDINGREQUESTID;
+ public static final String PROCESS_ENGINE_SERVICE_PROVIDER_ENTITYID = PROCESS_ENGINE_PREFIX + "uniqueSPId";
+ public static final String PROCESS_ENGINE_SSL_CLIENT_CERTIFICATE = PROCESS_ENGINE_PREFIX + "holderofkey_cert";
+
+ public static final int ALLOWED_TIME_JITTER = 5; //minutes
+ public static final String COUNTRYCODE_AUSTRIA = "AT";
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/ExceptionContainer.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/ExceptionContainer.java
new file mode 100644
index 00000000..1b16d4c2
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/ExceptionContainer.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.data;
+
+import java.io.Serializable;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+
+/**
+ * @author tlenz
+ *
+ */
+public class ExceptionContainer implements Serializable {
+
+ private static final long serialVersionUID = 5355860753609684995L;
+ private Throwable exceptionThrown = null;
+ private IRequest pendingReq = null;
+
+
+ /**
+ *
+ */
+ public ExceptionContainer(IRequest pendingReq, Throwable exception) {
+ this.pendingReq = pendingReq;
+ this.exceptionThrown = exception;
+
+ }
+
+ /**
+ * @return the exceptionThrown
+ */
+ public Throwable getExceptionThrown() {
+ return this.exceptionThrown;
+ }
+
+ public IRequest getPendingRequest() {
+ return this.pendingReq;
+
+ }
+
+ /**
+ * @return the uniqueSessionID
+ */
+ public String getUniqueSessionID() {
+ if (this.pendingReq != null)
+ return this.pendingReq.getUniqueSessionIdentifier();
+ else
+ return null;
+ }
+ /**
+ * @return the uniqueTransactionID
+ */
+ public String getUniqueTransactionID() {
+ if (this.pendingReq != null)
+ return this.pendingReq.getUniqueTransactionIdentifier();
+ else
+ return null;
+ }
+
+ /**
+ * @return the uniqueServiceProviderId
+ */
+ public String getUniqueServiceProviderId() {
+ if (this.pendingReq != null &&
+ this.pendingReq.getServiceProviderConfiguration() != null)
+ return this.pendingReq.getServiceProviderConfiguration().getUniqueIdentifier();
+ else
+ return null;
+ }
+
+
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/ILoALevelMapper.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/ILoALevelMapper.java
new file mode 100644
index 00000000..d4f49916
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/ILoALevelMapper.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.data;
+
+public interface ILoALevelMapper {
+
+ /**
+ * Map an arbitrary QAA level to eIDAS LoA
+ *
+ * @param qaa, but not null
+ * @return An eIDAS LoA if there is a mapping, otherwise null
+ */
+ public String mapToeIDASLoA(String qaa);
+
+ /**
+ * Map an arbitrary QAA level to PVP SecClass
+ *
+ * @param qaa, but not null
+ * @return An PVP SecClass if there is a mapping, otherwise null
+ */
+ public String mapToSecClass(String qaa);
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/PVPAttributeDefinitions.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/PVPAttributeDefinitions.java
new file mode 100644
index 00000000..9a439072
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/PVPAttributeDefinitions.java
@@ -0,0 +1,251 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.data;
+
+public interface PVPAttributeDefinitions {
+
+ public static final String URN_OID_PREFIX = "urn:oid:";
+
+ public static final String PVP_VERSION_OID = "1.2.40.0.10.2.1.1.261.10";
+ public static final String PVP_VERSION_NAME = URN_OID_PREFIX + PVP_VERSION_OID;
+ public static final String PVP_VERSION_FRIENDLY_NAME = "PVP-VERSION";
+ public static final String PVP_VERSION_2_1 = "2.1";
+
+
+ public static final String SECCLASS_OID = "1.2.40.0.10.2.1.1.261.110";
+ public static final String SECCLASS_FRIENDLY_NAME = "SECCLASS";
+ public static final String SECCLASS_NAME = URN_OID_PREFIX + SECCLASS_OID;
+ public static final int SECCLASS_MAX_LENGTH = 128;
+
+ public static final String PRINCIPAL_NAME_OID = "1.2.40.0.10.2.1.1.261.20";
+ public static final String PRINCIPAL_NAME_NAME = URN_OID_PREFIX + PRINCIPAL_NAME_OID;
+ public static final String PRINCIPAL_NAME_FRIENDLY_NAME = "PRINCIPAL-NAME";
+ public static final int PRINCIPAL_NAME_MAX_LENGTH = 128;
+
+ public static final String GIVEN_NAME_OID = "2.5.4.42";
+ public static final String GIVEN_NAME_NAME = URN_OID_PREFIX + GIVEN_NAME_OID;
+ public static final String GIVEN_NAME_FRIENDLY_NAME = "GIVEN-NAME";
+ public static final int GIVEN_NAME_MAX_LENGTH = 128;
+
+ public static final String BIRTHDATE_OID = "1.2.40.0.10.2.1.1.55";
+ public static final String BIRTHDATE_NAME = URN_OID_PREFIX + BIRTHDATE_OID;
+ public static final String BIRTHDATE_FRIENDLY_NAME = "BIRTHDATE";
+ public static final String BIRTHDATE_FORMAT_PATTERN = "yyyy-MM-dd";
+
+ public static final String USERID_OID = "0.9.2342.19200300.100.1.1";
+ public static final String USERID_NAME = URN_OID_PREFIX + USERID_OID;
+ public static final String USERID_FRIENDLY_NAME = "USERID";
+ public static final int USERID_MAX_LENGTH = 128;
+
+ public static final String GID_OID = "1.2.40.0.10.2.1.1.1";
+ public static final String GID_NAME = URN_OID_PREFIX + GID_OID;
+ public static final String GID_FRIENDLY_NAME = "GID";
+ public static final int GID_MAX_LENGTH = 128;
+
+ public static final String BPK_OID = "1.2.40.0.10.2.1.1.149";
+ public static final String BPK_NAME = URN_OID_PREFIX + BPK_OID;
+ public static final String BPK_FRIENDLY_NAME = "BPK";
+ public static final int BPK_MAX_LENGTH = 1024;
+
+ public static final String ENC_BPK_LIST_OID = "1.2.40.0.10.2.1.1.261.22";
+ public static final String ENC_BPK_LIST_NAME = URN_OID_PREFIX+ENC_BPK_LIST_OID;
+ public static final String ENC_BPK_LIST_FRIENDLY_NAME = "ENC-BPK-LIST";
+ public static final int ENC_BPK_LIST_MAX_LENGTH = 32767;
+
+ public static final String MAIL_OID = "0.9.2342.19200300.100.1.3";
+ public static final String MAIL_NAME = URN_OID_PREFIX + MAIL_OID;
+ public static final String MAIL_FRIENDLY_NAME = "MAIL";
+ public static final int MAIL_MAX_LENGTH = 128;
+
+ public static final String TEL_OID = "2.5.4.20";
+ public static final String TEL_NAME = URN_OID_PREFIX + TEL_OID;
+ public static final String TEL_FRIENDLY_NAME = "TEL";
+ public static final int TEL_MAX_LENGTH = 32;
+
+ public static final String PARTICIPANT_ID_OID = "1.2.40.0.10.2.1.1.71";
+ public static final String PARTICIPANT_ID_NAME = URN_OID_PREFIX + PARTICIPANT_ID_OID;
+ public static final String PARTICIPANT_ID_FRIENDLY_NAME = "PARTICIPANT-ID";
+ public static final int PARTICIPANT_MAX_LENGTH = 39;
+
+ public static final String PARTICIPANT_OKZ_OID = "1.2.40.0.10.2.1.1.261.24";
+ public static final String PARTICIPANT_OKZ_NAME = URN_OID_PREFIX + PARTICIPANT_OKZ_OID;
+ public static final String PARTICIPANT_OKZ_FRIENDLY_NAME = "PARTICIPANT-OKZ";
+ public static final int PARTICIPANT_OKZ_MAX_LENGTH = 32;
+
+ public static final String OU_OKZ_OID = "1.2.40.0.10.2.1.1.153";
+ public static final String OU_OKZ_NAME = URN_OID_PREFIX + OU_OKZ_OID;
+ public static final int OU_OKZ_MAX_LENGTH = 32;
+
+ public static final String OU_GV_OU_ID_OID = "1.2.40.0.10.2.1.1.3";
+ public static final String OU_GV_OU_ID_NAME = URN_OID_PREFIX + OU_GV_OU_ID_OID;
+ public static final String OU_GV_OU_ID_FRIENDLY_NAME = "OU-GV-OU-ID";
+ public static final int OU_GV_OU_ID_MAX_LENGTH = 39;
+
+ public static final String OU_OID = "2.5.4.11";
+ public static final String OU_NAME = URN_OID_PREFIX + OU_OID;
+ public static final String OU_FRIENDLY_NAME = "OU";
+ public static final int OU_MAX_LENGTH = 64;
+
+ public static final String FUNCTION_OID = "1.2.40.0.10.2.1.1.33";
+ public static final String FUNCTION_NAME = URN_OID_PREFIX + FUNCTION_OID;
+ public static final String FUNCTION_FRIENDLY_NAME = "FUNCTION";
+ public static final int FUNCTION_MAX_LENGTH = 32;
+
+ public static final String ROLES_OID = "1.2.40.0.10.2.1.1.261.30";
+ public static final String ROLES_NAME = URN_OID_PREFIX + ROLES_OID;
+ public static final String ROLES_FRIENDLY_NAME = "ROLES";
+ public static final int ROLES_MAX_LENGTH = 32767;
+
+ @Deprecated public static final String EID_CITIZEN_QAA_LEVEL_OID = "1.2.40.0.10.2.1.1.261.94";
+ @Deprecated public static final String EID_CITIZEN_QAA_LEVEL_NAME = URN_OID_PREFIX + EID_CITIZEN_QAA_LEVEL_OID;
+ @Deprecated public static final String EID_CITIZEN_QAA_LEVEL_FRIENDLY_NAME = "EID-CITIZEN-QAA-LEVEL";
+
+ public static final String EID_CITIZEN_EIDAS_QAA_LEVEL_OID = "1.2.40.0.10.2.1.1.261.108";
+ public static final String EID_CITIZEN_EIDAS_QAA_LEVEL_NAME = URN_OID_PREFIX + EID_CITIZEN_EIDAS_QAA_LEVEL_OID;
+ public static final String EID_CITIZEN_EIDAS_QAA_LEVEL_FRIENDLY_NAME = "EID-CITIZEN-QAA-EIDAS-LEVEL";
+
+ public static final String EID_ISSUING_NATION_OID = "1.2.40.0.10.2.1.1.261.32";
+ public static final String EID_ISSUING_NATION_NAME = URN_OID_PREFIX + EID_ISSUING_NATION_OID;
+ public static final String EID_ISSUING_NATION_FRIENDLY_NAME = "EID-ISSUING-NATION";
+ public static final int EID_ISSUING_NATION_MAX_LENGTH = 2;
+
+ public static final String EID_SECTOR_FOR_IDENTIFIER_OID = "1.2.40.0.10.2.1.1.261.34";
+ public static final String EID_SECTOR_FOR_IDENTIFIER_NAME = URN_OID_PREFIX + EID_SECTOR_FOR_IDENTIFIER_OID;
+ public static final String EID_SECTOR_FOR_IDENTIFIER_FRIENDLY_NAME = "EID-SECTOR-FOR-IDENTIFIER";
+ public static final int EID_SECTOR_FOR_IDENTIFIER_MAX_LENGTH = 255;
+
+ public static final String EID_SOURCE_PIN_OID = "1.2.40.0.10.2.1.1.261.36";
+ public static final String EID_SOURCE_PIN_NAME = URN_OID_PREFIX + EID_SOURCE_PIN_OID;
+ public static final String EID_SOURCE_PIN_FRIENDLY_NAME = "EID-SOURCE-PIN";
+ public static final int EID_SOURCE_PIN_MAX_LENGTH = 128;
+
+ public static final String EID_SOURCE_PIN_TYPE_OID = "1.2.40.0.10.2.1.1.261.104";
+ public static final String EID_SOURCE_PIN_TYPE_NAME = URN_OID_PREFIX + EID_SOURCE_PIN_TYPE_OID;
+ public static final String EID_SOURCE_PIN_TYPE_FRIENDLY_NAME = "EID-SOURCE-PIN-TYPE";
+ public static final int EID_SOURCE_PIN_TYPE_MAX_LENGTH = 128;
+
+ public static final String EID_IDENTITY_LINK_OID = "1.2.40.0.10.2.1.1.261.38";
+ public static final String EID_IDENTITY_LINK_NAME = URN_OID_PREFIX + EID_IDENTITY_LINK_OID;
+ public static final String EID_IDENTITY_LINK_FRIENDLY_NAME = "EID-IDENTITY-LINK";
+ public static final int EID_IDENTITY_LINK_MAX_LENGTH = 32767;
+
+ public static final String EID_AUTH_BLOCK_OID = "1.2.40.0.10.2.1.1.261.62";
+ public static final String EID_AUTH_BLOCK_NAME = URN_OID_PREFIX + EID_AUTH_BLOCK_OID;
+ public static final String EID_AUTH_BLOCK_FRIENDLY_NAME = "EID-AUTH-BLOCK";
+ public static final int EID_AUTH_BLOCK_MAX_LENGTH = 32767;
+
+ public static final String EID_CCS_URL_OID = "1.2.40.0.10.2.1.1.261.64";
+ public static final String EID_CCS_URL_NAME = URN_OID_PREFIX + EID_CCS_URL_OID;
+ public static final String EID_CCS_URL_FRIENDLY_NAME = "EID-CCS-URL";
+ public static final int EID_CCS_URL_MAX_LENGTH = 1024;
+
+ public static final String EID_SIGNER_CERTIFICATE_OID = "1.2.40.0.10.2.1.1.261.66";
+ public static final String EID_SIGNER_CERTIFICATE_NAME = URN_OID_PREFIX + EID_SIGNER_CERTIFICATE_OID;
+ public static final String EID_SIGNER_CERTIFICATE_FRIENDLY_NAME = "EID-SIGNER-CERTIFICATE";
+ public static final int EID_SIGNER_CERTIFICATE_MAX_LENGTH = 32767;
+
+ public static final String EID_STORK_TOKEN_OID = "1.2.40.0.10.2.1.1.261.96";
+ public static final String EID_STORK_TOKEN_NAME = URN_OID_PREFIX + EID_STORK_TOKEN_OID;
+ public static final String EID_STORK_TOKEN_FRIENDLY_NAME = "EID-STORK-TOKEN";
+ public static final int EID_STORK_TOKEN_MAX_LENGTH = 32767;
+
+ public static final String MANDATE_TYPE_OID = "1.2.40.0.10.2.1.1.261.68";
+ public static final String MANDATE_TYPE_NAME = URN_OID_PREFIX + MANDATE_TYPE_OID;
+ public static final String MANDATE_TYPE_FRIENDLY_NAME = "MANDATE-TYPE";
+ public static final int MANDATE_TYPE_MAX_LENGTH = 256;
+
+ public static final String MANDATE_TYPE_OID_OID = "1.2.40.0.10.2.1.1.261.106";
+ public static final String MANDATE_TYPE_OID_NAME = URN_OID_PREFIX + MANDATE_TYPE_OID_OID;
+ public static final String MANDATE_TYPE_OID_FRIENDLY_NAME = "MANDATE-TYPE-OID";
+ public static final int MANDATE_TYPE_OID_MAX_LENGTH = 256;
+
+ public static final String MANDATE_NAT_PER_SOURCE_PIN_OID = "1.2.40.0.10.2.1.1.261.70";
+ public static final String MANDATE_NAT_PER_SOURCE_PIN_NAME = URN_OID_PREFIX + MANDATE_NAT_PER_SOURCE_PIN_OID;
+ public static final String MANDATE_NAT_PER_SOURCE_PIN_FRIENDLY_NAME = "MANDATOR-NATURAL-PERSON-SOURCE-PIN";
+ public static final int MANDATE_NAT_PER_SOURCE_PIN_MAX_LENGTH = 128;
+
+ public static final String MANDATE_LEG_PER_SOURCE_PIN_OID = "1.2.40.0.10.2.1.1.261.100";
+ public static final String MANDATE_LEG_PER_SOURCE_PIN_NAME = URN_OID_PREFIX + MANDATE_LEG_PER_SOURCE_PIN_OID;
+ public static final String MANDATE_LEG_PER_SOURCE_PIN_FRIENDLY_NAME = "MANDATOR-LEGAL-PERSON-SOURCE-PIN";
+ public static final int MANDATE_LEG_PER_SOURCE_PIN_MAX_LENGTH = 128;
+
+ public static final String MANDATE_NAT_PER_SOURCE_PIN_TYPE_OID = "1.2.40.0.10.2.1.1.261.102";
+ public static final String MANDATE_NAT_PER_SOURCE_PIN_TYPE_NAME = URN_OID_PREFIX + MANDATE_NAT_PER_SOURCE_PIN_TYPE_OID;
+ public static final String MANDATE_NAT_PER_SOURCE_PIN_TYPE_FRIENDLY_NAME = "MANDATOR-NATURAL-PERSON-SOURCE-PIN-TYPE";
+ public static final int MANDATE_NAT_PER_SOURCE_PIN_TYPE_MAX_LENGTH = 128;
+
+ public static final String MANDATE_LEG_PER_SOURCE_PIN_TYPE_OID = "1.2.40.0.10.2.1.1.261.76";
+ public static final String MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME = URN_OID_PREFIX + MANDATE_LEG_PER_SOURCE_PIN_TYPE_OID;
+ public static final String MANDATE_LEG_PER_SOURCE_PIN_TYPE_FRIENDLY_NAME = "MANDATOR-LEGAL-PERSON-SOURCE-PIN-TYPE";
+ public static final int MANDATE_LEG_PER_SOURCE_PIN_TYPE_MAX_LENGTH = 128;
+
+ public static final String MANDATE_NAT_PER_BPK_OID = "1.2.40.0.10.2.1.1.261.98";
+ public static final String MANDATE_NAT_PER_BPK_NAME = URN_OID_PREFIX + MANDATE_NAT_PER_BPK_OID;
+ public static final String MANDATE_NAT_PER_BPK_FRIENDLY_NAME = "MANDATOR-NATURAL-PERSON-BPK";
+ public static final int MANDATE_NAT_PER_BPK_MAX_LENGTH = 1024;
+
+ public static final String MANDATE_NAT_PER_ENC_BPK_LIST_OID = "1.2.40.0.10.2.1.1.261.72";
+ public static final String MANDATE_NAT_PER_ENC_BPK_LIST_NAME = URN_OID_PREFIX + MANDATE_NAT_PER_ENC_BPK_LIST_OID;
+ public static final String MANDATE_NAT_PER_ENC_BPK_LIST_FRIENDLY_NAME = "MANDATOR-NATURAL-PERSON-ENC-BPK-LIST";
+ public static final int MANDATE_NAT_PER_ENC_BPK_LIST_MAX_LENGTH = 32767;
+
+ public static final String MANDATE_NAT_PER_GIVEN_NAME_OID = "1.2.40.0.10.2.1.1.261.78";
+ public static final String MANDATE_NAT_PER_GIVEN_NAME_NAME = URN_OID_PREFIX + MANDATE_NAT_PER_GIVEN_NAME_OID;
+ public static final String MANDATE_NAT_PER_GIVEN_NAME_FRIENDLY_NAME = "MANDATOR-NATURAL-PERSON-GIVEN-NAME";
+ public static final int MANDATE_NAT_PER_GIVEN_NAME_MAX_LENGTH = 128;
+
+ public static final String MANDATE_NAT_PER_FAMILY_NAME_OID = "1.2.40.0.10.2.1.1.261.80";
+ public static final String MANDATE_NAT_PER_FAMILY_NAME_NAME = URN_OID_PREFIX + MANDATE_NAT_PER_FAMILY_NAME_OID;
+ public static final String MANDATE_NAT_PER_FAMILY_NAME_FRIENDLY_NAME = "MANDATOR-NATURAL-PERSON-FAMILY-NAME";
+ public static final int MANDATE_NAT_PER_FAMILY_NAME_MAX_LENGTH = 128;
+
+ public static final String MANDATE_NAT_PER_BIRTHDATE_OID = "1.2.40.0.10.2.1.1.261.82";
+ public static final String MANDATE_NAT_PER_BIRTHDATE_NAME = URN_OID_PREFIX + MANDATE_NAT_PER_BIRTHDATE_OID;
+ public static final String MANDATE_NAT_PER_BIRTHDATE_FRIENDLY_NAME = "MANDATOR-NATURAL-PERSON-BIRTHDATE";
+ public static final String MANDATE_NAT_PER_BIRTHDATE_FORMAT_PATTERN = BIRTHDATE_FORMAT_PATTERN;
+
+ public static final String MANDATE_LEG_PER_FULL_NAME_OID = "1.2.40.0.10.2.1.1.261.84";
+ public static final String MANDATE_LEG_PER_FULL_NAME_NAME = URN_OID_PREFIX + MANDATE_LEG_PER_FULL_NAME_OID;
+ public static final String MANDATE_LEG_PER_FULL_NAME_FRIENDLY_NAME = "MANDATOR-LEGAL-PERSON-FULL-NAME";
+ public static final int MANDATE_LEG_PER_FULL_NAME_MAX_LENGTH = 256;
+
+ public static final String MANDATE_PROF_REP_OID_OID = "1.2.40.0.10.2.1.1.261.86";
+ public static final String MANDATE_PROF_REP_OID_NAME = URN_OID_PREFIX + MANDATE_PROF_REP_OID_OID;
+ public static final String MANDATE_PROF_REP_OID_FRIENDLY_NAME = "MANDATE-PROF-REP-OID";
+ public static final int MANDATE_PROF_REP_OID_MAX_LENGTH = 256;
+
+ public static final String MANDATE_PROF_REP_DESC_OID = "1.2.40.0.10.2.1.1.261.88";
+ public static final String MANDATE_PROF_REP_DESC_NAME = URN_OID_PREFIX + MANDATE_PROF_REP_DESC_OID;
+ public static final String MANDATE_PROF_REP_DESC_FRIENDLY_NAME = "MANDATE-PROF-REP-DESCRIPTION";
+ public static final int MANDATE_PROF_REP_DESC_MAX_LENGTH = 1024;
+
+ public static final String MANDATE_REFERENCE_VALUE_OID = "1.2.40.0.10.2.1.1.261.90";
+ public static final String MANDATE_REFERENCE_VALUE_NAME = URN_OID_PREFIX + MANDATE_REFERENCE_VALUE_OID;
+ public static final String MANDATE_REFERENCE_VALUE_FRIENDLY_NAME = "MANDATE-REFERENCE-VALUE";
+ public static final int MANDATE_REFERENCE_VALUE_MAX_LENGTH = 100;
+
+ public static final String MANDATE_FULL_MANDATE_OID = "1.2.40.0.10.2.1.1.261.92";
+ public static final String MANDATE_FULL_MANDATE_NAME = URN_OID_PREFIX + MANDATE_FULL_MANDATE_OID;
+ public static final String MANDATE_FULL_MANDATE_FRIENDLY_NAME = "MANDATE-FULL-MANDATE";
+ public static final int MANDATE_FULL_MANDATE_MAX_LENGTH = 32767;
+
+ public static final String INVOICE_RECPT_ID_OID = "1.2.40.0.10.2.1.1.261.40";
+ public static final String INVOICE_RECPT_ID_NAME = URN_OID_PREFIX + INVOICE_RECPT_ID_OID;
+ public static final String INVOICE_RECPT_ID_FRIENDLY_NAME = "INVOICE-RECPT-ID";
+ public static final int INVOICE_RECPT_ID_MAX_LENGTH = 64;
+
+ public static final String COST_CENTER_ID_OID = "1.2.40.0.10.2.1.1.261.50";
+ public static final String COST_CENTER_ID_NAME = URN_OID_PREFIX + COST_CENTER_ID_OID;
+ public static final String COST_CENTER_ID_FRIENDLY_NAME = "COST-CENTER-ID";
+ public static final int COST_CENTER_ID_MAX_LENGTH = 32767;
+
+ public static final String CHARGE_CODE_OID = "1.2.40.0.10.2.1.1.261.60";
+ public static final String CHARGE_CODE_NAME = URN_OID_PREFIX + CHARGE_CODE_OID;
+ public static final String CHARGE_CODE_FRIENDLY_NAME = "CHARGE-CODE";
+ public static final int CHARGE_CODE_MAX_LENGTH = 32767;
+
+ public static final String PVP_HOLDEROFKEY_OID = "1.2.40.0.10.2.1.1.261.xx.xx";
+ public static final String PVP_HOLDEROFKEY_NAME = URN_OID_PREFIX + PVP_HOLDEROFKEY_OID;
+ public static final String PVP_HOLDEROFKEY_FRIENDLY_NAME = "HOLDER-OF-KEY-CERTIFICATE";
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/XMLNamespaceConstants.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/XMLNamespaceConstants.java
new file mode 100644
index 00000000..4ed321bd
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/data/XMLNamespaceConstants.java
@@ -0,0 +1,474 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.api.data;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Contains various constants used throughout the system.
+
+ */
+public interface XMLNamespaceConstants {
+ /** Root location of the schema files. */
+ public static final String SCHEMA_ROOT = "/schemas/";
+
+ /** URI of the Widerrufregister XML namespace. */
+ public static final String WRR_NS_URI =
+ "http://reference.e-government.gv.at/namespace/moavv/20041223";
+
+ /** Prefix used for the Widerrufregister XML namespace */
+ public static final String WRR_PREFIX = "wrr";
+
+ /** URI of the StandardTextBlock XML namespace. */
+ public static final String STB_NS_URI =
+ "http://reference.e-government.gv.at/namespace/standardtextblock/20041105#";
+
+ /** Prefix used for the standard text block XML namespace */
+ public static final String STB_PREFIX = "stb";
+
+ /** URI of the MOA XML namespace. */
+ public static final String MOA_NS_URI =
+ "http://reference.e-government.gv.at/namespace/moa/20020822#";
+
+ /** Name of the mandates infobox */
+ public static final String INFOBOXIDENTIFIER_MANDATES = "Mandates";
+
+ /** Prefix used for the Mandate XML namespace */
+ public static final String MD_PREFIX = "md";
+
+ /** URI of the Mandate XML namespace. */
+ public static final String MD_NS_URI =
+ "http://reference.e-government.gv.at/namespace/mandates/20040701#";
+
+ /** Prefix used for the Mandate XML namespace */
+ public static final String MVV_PREFIX = "mvv";
+
+ /** URI of the Mandate XML namespace. */
+ public static final String MVV_NS_URI =
+ "http://reference.e-government.gv.at/namespace/moavv/app2mvv/20041125";
+
+ /** Prefix used for the MandateCheckProfile XML namespace */
+ public static final String MDP_PREFIX = "mdp";
+
+ /** URI of the Mandate XML namespace. */
+ public static final String MDP_NS_URI =
+ "http://reference.e-government.gv.at/namespace/mandateprofile/20041105#";
+
+ /** Prefix used for the MOA XML namespace */
+ public static final String MOA_PREFIX = "moa";
+
+ /** Local location of the MOA XML schema definition. */
+ public static final String MOA_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "MOA-SPSS-2.0.0.xsd";
+
+ /** URI of the MOA configuration XML namespace. */
+ public static final String MOA_CONFIG_NS_URI =
+ "http://reference.e-government.gv.at/namespace/moaconfig/20021122#";
+
+ /** URI of the MOA ID configuration XML namespace. */
+ public static final String MOA_ID_CONFIG_NS_URI =
+ "http://www.buergerkarte.at/namespaces/moaconfig#";
+
+ /** Prefix used for the MOA configuration XML namespace */
+ public static final String MOA_CONFIG_PREFIX = "conf";
+
+ /** Prefix used for the MOA configuration XML namespace */
+ public static final String MOA_ID_CONFIG_PREFIX = "confID";
+
+ /** Local location of the MOA configuration XML schema definition. */
+ public static final String MOA_CONFIG_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "MOA-SPSS-config-2.0.0.xsd";
+
+ /** Local location of the MOA ID configuration XML schema definition. */
+ public static final String MOA_ID_CONFIG_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "MOA-ID-Configuration-1.5.2.xsd";
+
+ /** URI of the Security Layer 1.0 namespace. */
+ public static final String SL10_NS_URI =
+ "http://www.buergerkarte.at/namespaces/securitylayer/20020225#";
+
+ /** Prefix used for the Security Layer 1.0 XML namespace */
+ public static final String SL10_PREFIX = "sl10";
+
+ /** Local location of the Security Layer 1.0 XML schema definition */
+ public static final String SL10_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "Core.20020225.xsd";
+
+ /** URI of the Security Layer 1.1 XML namespace */
+ public static final String SL11_NS_URI =
+ "http://www.buergerkarte.at/namespaces/securitylayer/20020831#";
+
+ /** Prefix used for the Security Layer 1.1 XML namespace */
+ public static final String SL11_PREFIX = "sl11";
+
+ /** Local location of the Security Layer 1.1 XML schema definition */
+ public static final String SL11_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "Core.20020831.xsd";
+
+ /** URI of the Security Layer 1.2 XML namespace */
+ public static final String SL12_NS_URI =
+ "http://www.buergerkarte.at/namespaces/securitylayer/1.2#";
+
+ /** Prefix used for the Security Layer 1.2 XML namespace */
+ public static final String SL12_PREFIX = "sl";
+
+ /** Local location of the Security Layer 1.2 XML schema definition */
+ public static final String SL12_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "Core-1.2.xsd";
+
+ /** URI of the ECDSA XML namespace */
+ public static final String ECDSA_NS_URI =
+ "http://www.w3.org/2001/04/xmldsig-more#";
+
+ /** Prefix used for ECDSA namespace */
+ public static final String ECDSA_PREFIX = "ecdsa";
+
+ /** Local location of ECDSA XML schema definition */
+ public static final String ECDSA_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "ECDSAKeyValue.xsd";
+
+ /** URI of the PersonData XML namespace. */
+ public static final String PD_NS_URI =
+ "http://reference.e-government.gv.at/namespace/persondata/20020228#";
+
+ /** Prefix used for the PersonData XML namespace */
+ public static final String PD_PREFIX = "pr";
+
+// /** Local location of the PersonData XML schema definition */
+// public static final String PD_SCHEMA_LOCATION =
+// SCHEMA_ROOT + "PersonData.xsd";
+
+ /** Local location of the PersonData XML schema definition */
+ public static final String PD_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "PersonData_20_en_moaWID.xsd";
+
+ /** URI of the SAML namespace. */
+ public static final String SAML_NS_URI =
+ "urn:oasis:names:tc:SAML:1.0:assertion";
+
+ /** Prefix used for the SAML XML namespace */
+ public static final String SAML_PREFIX = "saml";
+
+ /** Local location of the SAML XML schema definition. */
+ public static final String SAML_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "cs-sstc-schema-assertion-01.xsd";
+
+ /** URI of the SAML request-response protocol namespace. */
+ public static final String SAMLP_NS_URI =
+ "urn:oasis:names:tc:SAML:1.0:protocol";
+
+ /** Prefix used for the SAML request-response protocol namespace */
+ public static final String SAMLP_PREFIX = "samlp";
+
+ /** Local location of the SAML request-response protocol schema definition. */
+ public static final String SAMLP_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "cs-sstc-schema-protocol-01.xsd";
+
+ /** URI of the XML namespace. */
+ public static final String XML_NS_URI =
+ "http://www.w3.org/XML/1998/namespace";
+
+ /** Prefix used for the XML namespace */
+ public static final String XML_PREFIX = "xml";
+
+ /** Local location of the XML schema definition. */
+ public static final String XML_SCHEMA_LOCATION = SCHEMA_ROOT + "xml.xsd";
+
+ /** URI of the XMLNS namespace */
+ public static final String XMLNS_NS_URI = "http://www.w3.org/2000/xmlns/";
+
+ /** Prefix used for the XSI namespace */
+ public static final String XSI_PREFIX = "xsi";
+
+ /** Local location of the XSI schema definition. */
+ public static final String XSI_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "XMLSchema-instance.xsd";
+
+ /** URI of the XSI XMLNS namespace */
+ public static final String XSI_NS_URI =
+ "http://www.w3.org/2001/XMLSchema-instance";
+
+ /** URI of the XSLT XML namespace */
+ public static final String XSLT_NS_URI =
+ "http://www.w3.org/1999/XSL/Transform";
+
+ /** Prefix used for the XSLT XML namespace */
+ public static final String XSLT_PREFIX = "xsl";
+
+ /** URI of the XMLDSig XML namespace. */
+ public static final String DSIG_NS_URI = "http://www.w3.org/2000/09/xmldsig#";
+
+ /** Prefix used for the XMLDSig XML namespace */
+ public static final String DSIG_PREFIX = "dsig";
+
+ /** Local location of the XMLDSig XML schema. */
+ public static final String DSIG_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "xmldsig-core-schema.xsd";
+
+ /** URI of the XMLDSig XPath Filter XML namespace. */
+ public static final String DSIG_FILTER2_NS_URI =
+ "http://www.w3.org/2002/06/xmldsig-filter2";
+
+ /** Prefix used for the XMLDSig XPath Filter XML namespace */
+ public static final String DSIG_FILTER2_PREFIX = "dsig-filter2";
+
+ /** Local location of the XMLDSig XPath Filter XML schema definition. */
+ public static final String DSIG_FILTER2_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "xmldsig-filter2.xsd";
+
+ /** URI of the Exclusive Canonicalization XML namespace */
+ public static final String DSIG_EC_NS_URI =
+ "http://www.w3.org/2001/10/xml-exc-c14n#";
+
+ /** Prefix used for the Exclusive Canonicalization XML namespace */
+ public static final String DSIG_EC_PREFIX = "ec";
+
+ /** Local location of the Exclusive Canonicalizaion XML schema definition */
+ public static final String DSIG_EC_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "exclusive-canonicalization.xsd";
+
+ /** URI of the XMLLoginParameterResolver Configuration XML namespace */
+ public static final String XMLLPR_NS_URI="http://reference.e-government.gv.at/namespace/moa/20020822#/xmllpr20030814";
+
+ /** Local location of the XMLLoginParameterResolver Configuration XML schema definition */
+ public static final String XMLLPR_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "MOAIdentities.xsd";
+
+ /** Local location of the XAdES v1.1.1 schema definition */
+ public static final String XADES_1_1_1_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "XAdES-1.1.1.xsd";
+
+ /** URI of the XAdES v1.1.1 namespace */
+ public static final String XADES_1_1_1_NS_URI = "http://uri.etsi.org/01903/v1.1.1#";
+
+ public static final String XADES_1_1_1_NS_PREFIX = "xades111";
+
+ /** Local location of the XAdES v1.2.2 schema definition */
+ public static final String XADES_1_2_2_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "XAdES-1.2.2.xsd";
+
+ /** URI of the XAdES v1.2.2 namespace */
+ public static final String XADES_1_2_2_NS_URI = "http://uri.etsi.org/01903/v1.2.2#";
+
+ public static final String XADES_1_2_2_NS_PREFIX = "xades122";
+
+ /** Local location of the XAdES v1.1.1 schema definition */
+ public static final String XADES_1_3_2_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "XAdES-1.3.2.xsd";
+
+ /** URI of the XAdES v1.3.2 namespace */
+ public static final String XADES_1_3_2_NS_URI = "http://uri.etsi.org/01903/v1.3.2#";
+
+ public static final String XADES_1_3_2_NS_PREFIX = "xades132";
+
+ /** Local location of the XAdES v1.4.1 schema definition */
+ public static final String XADES_1_4_1_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "XAdES-1.4.1.xsd";
+
+ /** URI of the XAdES v1.4.1 namespace */
+ public static final String XADES_1_4_1_NS_URI = "http://uri.etsi.org/01903/v1.4.1#";
+
+ public static final String XADES_1_4_1_NS_PREFIX = "xades141";
+ /** URI of the SAML 2.0 namespace. */
+ public static final String SAML2_NS_URI =
+ "urn:oasis:names:tc:SAML:2.0:assertion";
+
+ /** Prefix used for the SAML 2.0 XML namespace */
+ public static final String SAML2_PREFIX = "saml2";
+
+ /** Local location of the SAML 2.0 XML schema definition. */
+ public static final String SAML2_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "saml-schema-assertion-2.0.xsd";
+
+ /** URI of the SAML 2.0 protocol namespace. */
+ public static final String SAML2P_NS_URI =
+ "urn:oasis:names:tc:SAML:2.0:protocol";
+
+ /** Prefix used for the SAML 2.0 protocol XML namespace */
+ public static final String SAML2P_PREFIX = "saml2p";
+
+ /** Local location of the SAML 2.0 protocol XML schema definition. */
+ public static final String SAML2P_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "saml-schema-protocol-2.0.xsd";
+
+ /** URI of the STORK namespace. */
+ public static final String STORK_NS_URI =
+ "urn:eu:stork:names:tc:STORK:1.0:assertion";
+
+ /** Prefix used for the STORK XML namespace */
+ public static final String STORK_PREFIX = "stork";
+
+ /** Local location of the STORK XML schema definition. */
+ public static final String STORK_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "stork-schema-assertion-1.0.xsd";
+
+ /** URI of the STORK protocol namespace. */
+ public static final String STORKP_NS_URI =
+ "urn:eu:stork:names:tc:STORK:1.0:protocol";
+
+ /** Prefix used for the STORK protocol XML namespace */
+ public static final String STORKP_PREFIX = "storkp";
+
+ /** Local location of the STORK protocol XML schema definition. */
+ public static final String STORKP_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "stork-schema-protocol-1.0.xsd";
+
+ /** URI of the TSL namespace. */
+ public static final String TSL_NS_URI =
+ "http://uri.etsi.org/02231/v2#";
+
+ /** Prefix used for the TSL namespace */
+ public static final String TSL_PREFIX = "tsl1";
+
+ /** Local location of the TSL schema definition. */
+ public static final String TSL_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "ts_119612v010201_xsd.xsd";
+
+ /** URI of the TSL SIE namespace. */
+ public static final String TSL_SIE_NS_URI =
+ "http://uri.etsi.org/TrstSvc/SvcInfoExt/eSigDir-1999-93-EC-TrustedList/#";
+
+ /** Prefix used for the TSL SIE namespace */
+ public static final String TSL_SIE_PREFIX = "tslsie";
+
+ /** Local location of the TSL SIE schema definition. */
+ public static final String TSL_SIE_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "ts_119612v010201_sie_xsd.xsd";
+
+ /** URI of the TSL additional types namespace. */
+ public static final String TSL_ADDTYPES_NS_URI =
+ "http://uri.etsi.org/02231/v2/additionaltypes#";
+
+ /** Prefix used for the TSL additional types namespace */
+ public static final String TSL_ADDTYPES_PREFIX = "tsltype";
+
+ /** Local location of the TSL additional types schema definition. */
+ public static final String TSL_ADDTYPES_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "ts_ts_119612v010201_additionaltypes_xsd.xsd";
+
+ /** URI of the XML Encryption namespace. */
+ public static final String XENC_NS_URI =
+ "http://www.w3.org/2001/04/xmlenc#";
+
+ /** Prefix used for the XML Encryption XML namespace */
+ public static final String XENC_PREFIX = "xenc";
+
+ /** Local location of the XML Encryption XML schema definition. */
+ public static final String XENC_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "xenc-schema.xsd";
+
+ /** Prefix used for the XML Encryption XML namespace */
+ public static final String SAML2_METADATA_PREFIX = "md";
+
+ /** Prefix used for the XML Encryption XML namespace */
+ public static final String SAML2_METADATA_URI = "urn:oasis:names:tc:SAML:2.0:metadata";
+
+ /** Local location of the XML Encryption XML schema definition. */
+ public static final String SAML2_METADATA_SCHEMA_LOCATION =
+ SCHEMA_ROOT + "saml-schema-metadata-2.0.xsd";
+
+
+ /* Prefix and Schema definition for eIDAS specific SAML2 extensions*/
+ public static final String SAML2_eIDAS_EXTENSIONS_PREFIX = "eidas";
+ public static final String SAML2_eIDAS_EXTENSIONS = "http://eidas.europa.eu/saml-extensions";
+ public static final String SAML2_eIDAS_EXTENSIONS_SCHEMA_LOCATION = SCHEMA_ROOT + "eIDAS_saml_extensions.xsd";
+
+
+ /* Prefix and Schema for SAML2 Entity Attributes */
+ public static final String SAML2_MDATTR_EXTENSIONS_PREFIX = "mdattr";
+ public static final String SAML2_MDATTR_EXTENSIONS = "urn:oasis:names:tc:SAML:metadata:attribute";
+ public static final String SAML2_MDATTR_EXTENSIONS_SCHEMA_LOCATION = SCHEMA_ROOT + "sstc-metadata-attr.xsd";
+
+ /**
+ * Contains all namespaces and local schema locations for XML schema
+ * definitions relevant for MOA. For use in validating XML parsers.
+ */
+ public static final String ALL_SCHEMA_LOCATIONS =
+ (MOA_NS_URI + " " + MOA_SCHEMA_LOCATION + " ")
+ + (MOA_CONFIG_NS_URI + " " + MOA_CONFIG_SCHEMA_LOCATION + " ")
+ + (MOA_ID_CONFIG_NS_URI + " " + MOA_ID_CONFIG_SCHEMA_LOCATION + " ")
+ + (SL10_NS_URI + " " + SL10_SCHEMA_LOCATION + " ")
+ + (SL11_NS_URI + " " + SL11_SCHEMA_LOCATION + " ")
+ + (SL12_NS_URI + " " + SL12_SCHEMA_LOCATION + " ")
+ + (ECDSA_NS_URI + " " + ECDSA_SCHEMA_LOCATION + " ")
+ + (PD_NS_URI + " " + PD_SCHEMA_LOCATION + " ")
+ + (SAML_NS_URI + " " + SAML_SCHEMA_LOCATION + " ")
+ + (SAMLP_NS_URI + " " + SAMLP_SCHEMA_LOCATION + " ")
+ + (XML_NS_URI + " " + XML_SCHEMA_LOCATION + " ")
+ + (XSI_NS_URI + " " + XSI_SCHEMA_LOCATION + " ")
+ + (DSIG_NS_URI + " " + DSIG_SCHEMA_LOCATION + " ")
+ + (DSIG_FILTER2_NS_URI + " " + DSIG_FILTER2_SCHEMA_LOCATION + " ")
+ + (DSIG_EC_NS_URI + " " + DSIG_EC_SCHEMA_LOCATION + " ")
+ + (XMLLPR_NS_URI + " " + XMLLPR_SCHEMA_LOCATION + " ")
+ + (XADES_1_1_1_NS_URI + " " + XADES_1_1_1_SCHEMA_LOCATION + " ")
+ + (XADES_1_2_2_NS_URI + " " + XADES_1_2_2_SCHEMA_LOCATION + " ")
+ + (XADES_1_3_2_NS_URI + " " + XADES_1_3_2_SCHEMA_LOCATION + " ")
+ + (XADES_1_4_1_NS_URI + " " + XADES_1_4_1_SCHEMA_LOCATION + " ")
+ + (TSL_NS_URI + " " + TSL_SCHEMA_LOCATION + " ")
+ + (TSL_SIE_NS_URI + " " + TSL_SIE_SCHEMA_LOCATION + " ")
+ + (TSL_ADDTYPES_NS_URI + " " + TSL_ADDTYPES_SCHEMA_LOCATION + " ")
+ + (SAML2_NS_URI + " " + SAML2_SCHEMA_LOCATION + " ")
+ + (SAML2P_NS_URI + " " + SAML2P_SCHEMA_LOCATION + " ")
+ + (STORK_NS_URI + " " + STORK_SCHEMA_LOCATION + " ")
+ + (STORKP_NS_URI + " " + STORKP_SCHEMA_LOCATION + " ")
+ + (SAML2_METADATA_URI + " " + SAML2_METADATA_SCHEMA_LOCATION + " ")
+ + (XENC_NS_URI + " " + XENC_SCHEMA_LOCATION + " ")
+ + (SAML2_eIDAS_EXTENSIONS + " " + SAML2_eIDAS_EXTENSIONS_SCHEMA_LOCATION + " ")
+ + (SAML2_MDATTR_EXTENSIONS + " " + SAML2_MDATTR_EXTENSIONS_SCHEMA_LOCATION);
+
+
+ /** Security Layer manifest type URI. */
+ public static final String SL_MANIFEST_TYPE_URI =
+ "http://www.buergerkarte.at/specifications/Security-Layer/20020225#SignatureManifest";
+
+ /** URI of the SHA1 digest algorithm */
+ public static final String SHA1_URI =
+ "http://www.w3.org/2000/09/xmldsig#sha1";
+
+ /** URI of the SHA1 digest algorithm */
+ public static final String SHA256_URI =
+ "http://www.w3.org/2000/09/xmldsig#sha256";
+
+ /** URI of the SHA1 digest algorithm */
+ public static final String SHA384_URI =
+ "http://www.w3.org/2000/09/xmldsig#sha384";
+
+ /** URI of the SHA1 digest algorithm */
+ public static final String SHA512_URI =
+ "http://www.w3.org/2000/09/xmldsig#sha512";
+
+ /** URI of the Canonical XML algorithm */
+ public static final String C14N_URI =
+ "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
+
+ /** URI of the Canoncial XML with comments algorithm */
+ public static final String C14N_WITH_COMMENTS_URI =
+ "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments";
+
+ /** URI of the Exclusive Canonical XML algorithm */
+ public static final String EXC_C14N_URI =
+ "http://www.w3.org/2001/10/xml-exc-c14n#";
+
+ /** URI of the Exclusive Canonical XML with commments algorithm */
+ public static final String EXC_C14N_WITH_COMMENTS_URI =
+ "http://www.w3.org/2001/10/xml-exc-c14n#WithComments";
+
+ /**
+ * A map used to map namespace prefixes to namespace URIs
+ */
+ public static final Map<String, String> nSMap = Collections.unmodifiableMap(new HashMap<String, String>(){
+ private static final long serialVersionUID = 3845384324295136490L;
+ {
+ put(XMLNamespaceConstants.SAML_PREFIX, XMLNamespaceConstants.SAML_NS_URI);
+ put(XMLNamespaceConstants.ECDSA_PREFIX, "http://www.w3.org/2001/04/xmldsig-more#");
+ put(XMLNamespaceConstants.DSIG_PREFIX, XMLNamespaceConstants.DSIG_NS_URI);
+ }
+ });
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIBuilderConfiguration.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIBuilderConfiguration.java
new file mode 100644
index 00000000..80a686f9
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIBuilderConfiguration.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.gui;
+
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface IGUIBuilderConfiguration {
+
+
+ /**
+ * Define the name of the template (with suffix) which should be used
+ *
+ * @return templatename, but never null
+ */
+ public String getViewName();
+
+ /**
+ * Define the parameters, which should be evaluated in the template
+ *
+ * @return Map of parameters, which should be added to template
+ */
+ public Map<String, Object> getViewParameters();
+
+
+ /**
+ * Get a specific classpath template-directory prefix, which is used
+ * to load a template from classpath by using <code>ClassLoader.getResourceAsStream(...)</code>
+ *
+ * @return Classpath directory, or null if the default directory should be used
+ */
+ public String getClasspathTemplateDir();
+
+ /**
+ * Get the GUI template with a specific name
+ *
+ * @param viewName Name of the template
+ * @return Tempate as <code>InputStream</code>, or null if default getTemplate method should be used
+ */
+ public InputStream getTemplate(String viewName);
+
+ /**
+ * Get the contentType, which should be set in HTTP response
+ * <br><br>
+ * <b>DefaultValue:</b> text/html;charset=UTF-8
+ *
+ * @return ContentType, or null if default ContentType should be used.
+ */
+ public String getDefaultContentType();
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIBuilderConfigurationFactory.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIBuilderConfigurationFactory.java
new file mode 100644
index 00000000..0d6b1470
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIBuilderConfigurationFactory.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.gui;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+
+public interface IGUIBuilderConfigurationFactory {
+
+ /**
+ * Get a DefaultGuiBuilderConfiguration to render an error message
+ *
+ * @param authURL PublicURLPrefix of the IDP but never null
+ * @return
+ */
+ public IGUIBuilderConfiguration getDefaultErrorGUI(String authURL);
+
+ /**
+ * @param Current processed pending-request but never null
+ * @param viewName Name of the default template (with suffix) but never null
+ * @param configRootContextDir Path to configuration root directory
+ * @return
+ * @throws MalformedURLException If configRootContextDir is not a valid URI
+ */
+ public IGUIBuilderConfiguration getSPSpecificSAML2PostConfiguration(IRequest pendingReq, String viewName, URI configRootContextDir)
+ throws MalformedURLException;
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIFormBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIFormBuilder.java
new file mode 100644
index 00000000..40238c2b
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/IGUIFormBuilder.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.gui;
+
+import java.io.InputStream;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.velocity.VelocityContext;
+
+import at.gv.egiz.eaaf.core.exceptions.GUIBuildException;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface IGUIFormBuilder {
+
+ /**
+ * Parse a GUI template, with parameters into a http servlet-response
+ * and use the default http-response content-type.
+ * <br><br>
+ * The parser use the <code>VelocityEngine</code> as internal template evaluator.
+ *
+ * @param httpResp http-response object
+ * @param viewName Name of the template (with suffix), which should be used.
+ * The template is selected by using the <code>getTemplate(String viewName)</code> method
+ * @param viewParams Map of parameters, which should be added to template
+ * @param loggerName String, which should be used from logger
+ *
+ * @throws GUIBuildException
+ */
+ public void build(HttpServletResponse httpResp, IGUIBuilderConfiguration config, String loggerName) throws GUIBuildException;
+
+ /**
+ * Parse a GUI template, with parameters into a http servlet-response.
+ * <br><br>
+ * The parser use the <code>VelocityEngine</code> as internal template evaluator.
+ *
+ * @param httpResp http-response object
+ * @param viewName Name of the template (with suffix), which should be used.
+ * The template is selected by using the <code>getTemplate(String viewName)</code> method
+ * @param viewParams Map of parameters, which should be added to template
+ * @param contentType http-response content-type, which should be set
+ * @param loggerName String, which should be used from logger
+ *
+ * @throws GUIBuildException
+ */
+ void build(HttpServletResponse httpResp, IGUIBuilderConfiguration config, String contentType,
+ String loggerName) throws GUIBuildException;
+
+
+ /**
+ * Generate a new {@link VelocityContext} and populate it with MOA-ID GUI parameters
+ *
+ * @param config
+ * @return
+ */
+ public VelocityContext generateVelocityContextFromConfiguration(IGUIBuilderConfiguration config);
+
+
+ /**
+ * Load the template from different resources
+ *
+ * @param config
+ * @return An {@link InputStream} but never null. The {@link InputStream} had to be closed be the invoking method
+ * @throws GUIBuildException
+ */
+ public InputStream getTemplateInputStream(IGUIBuilderConfiguration config) throws GUIBuildException;
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/ModifyableGuiBuilderConfiguration.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/ModifyableGuiBuilderConfiguration.java
new file mode 100644
index 00000000..3183ffad
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/gui/ModifyableGuiBuilderConfiguration.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.gui;
+
+public interface ModifyableGuiBuilderConfiguration {
+
+ /**
+ * Add a key/value pair into Velocity context.<br>
+ * <b>IMPORTANT:</b> external HTML escapetion is required, because it is NOT done internally
+ *
+ * @param key velocity context key
+ * @param value of this key
+ */
+ void putCustomParameterWithOutEscaption(String key, Object value);
+
+ /**
+ * Add a key/value pair into Velocity context.<br>
+ * All parameters get escaped internally
+ *
+ * @param key velocity context key
+ * @param value of this key
+ */
+ void putCustomParameter(String key, String value);
+
+} \ No newline at end of file
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/EAAFAuthProcessDataConstants.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/EAAFAuthProcessDataConstants.java
new file mode 100644
index 00000000..f7a9a847
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/EAAFAuthProcessDataConstants.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp;
+
+public interface EAAFAuthProcessDataConstants {
+
+ public static final String GENERIC_PREFIX = "generic_";
+
+ public static final String VALUE_ISSUEINSTANT = "direct_issueInstant";
+
+ public static final String FLAG_IS_AUTHENTICATED = "direct_flagIsAuth";
+ public static final String FLAG_IS_FOREIGNER = "direct_flagIsForeigner";
+ public static final String FLAG_USE_MANDATE = "direct_flagUseMandate";
+ public static final String FLAG_IS_ORGANWALTER = "direct_flagOrganwalter";
+
+ public static final String VALUE_IDENTITYLINK = "direct_idl";
+ public static final String VALUE_QAALEVEL = "direct_qaaLevel";
+ public static final String VALUE_MISMANDATE = "direct_MIS_Mandate";
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAction.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAction.java
new file mode 100644
index 00000000..c8d55b96
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAction.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ *******************************************************************************/
+/*******************************************************************************
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+
+
+/**
+ * Basic interface of a specific operation that is requested by an authentication protocol implementation
+ *
+ * @author tlenz
+ *
+ */
+public interface IAction {
+ public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, IAuthData authData)
+ throws EAAFException;
+ public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp);
+
+ public String getDefaultActionName();
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAttributeBuilder.java
new file mode 100644
index 00000000..ded9731c
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAttributeBuilder.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ *******************************************************************************/
+/*******************************************************************************
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp;
+
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+
+public interface IAttributeBuilder {
+ public String getName();
+
+ public <ATT> ATT build(final ISPConfiguration oaParam, final IAuthData authData,
+ final IAttributeGenerator<ATT> g) throws AttributeBuilderException;
+
+ public <ATT> ATT buildEmpty(final IAttributeGenerator<ATT> g);
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAttributeGenerator.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAttributeGenerator.java
new file mode 100644
index 00000000..01bb68cc
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAttributeGenerator.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ *******************************************************************************/
+/*******************************************************************************
+
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp;
+
+public interface IAttributeGenerator<ATT> {
+ /**
+ *
+ * @param friendlyName FriendlyName
+ * @param name Name
+ * @param value value
+ * @return
+ */
+ public abstract ATT buildStringAttribute(final String friendlyName, final String name, final String value);
+
+ public abstract ATT buildIntegerAttribute(final String friendlyName, final String name, final int value);
+
+ public abstract ATT buildLongAttribute(final String friendlyName, final String name, final long value);
+
+ public abstract ATT buildEmptyAttribute(final String friendlyName, final String name);
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAuthData.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAuthData.java
new file mode 100644
index 00000000..888b6e92
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAuthData.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ *******************************************************************************/
+/**
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egiz.eaaf.core.api.idp;
+
+import java.util.Date;
+
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface IAuthData {
+
+ /**
+ * BaseId transfer policy
+ *
+ * @return true if baseID transfer to service provider is allowed, otherwise false
+ */
+ boolean isBaseIDTransferRestrication();
+
+ /**
+ * Identifier of the IDP that authenicates the user
+ *
+ * @return
+ */
+ String getAuthenticationIssuer();
+
+ /**
+ * Timestamp of the authentication process
+ *
+ * @return
+ */
+ Date getAuthenticationIssueInstant();
+
+ /**
+ * Get string formated timestamp of the authentication process
+ *
+ * @return
+ */
+ String getAuthenticationIssueInstantString();
+
+
+ /**
+ * Familyname of the user
+ *
+ * @return
+ */
+ String getFamilyName();
+
+ /**
+ * Givenname of the user
+ *
+ * @return
+ */
+ String getGivenName();
+
+ /**
+ * Date of birth of the user
+ *
+ * @return date of birth or null no data of birth is available
+ */
+ Date getDateOfBirth();
+
+ /**
+ * String formated date of birth of the user with pattern yyyy-MM-dd
+ *
+ *
+ * @return date of birth or '2999-12-31' if no data of birth is available
+ */
+ String getFormatedDateOfBirth();
+
+ /**
+ * Get bPK of the user
+ *
+ * @return
+ */
+ String getBPK();
+
+ /**
+ * Get sector for user's bPK
+ *
+ *
+ * @return Sector identifier with prefix
+ */
+ String getBPKType();
+
+ /**
+ * Get baseId of this user
+ *
+ * @return
+ */
+ String getIdentificationValue();
+
+ /**
+ * Get type identifier of the baseId
+ * By default, this type is urn:publicid:gv.at:baseid
+ *
+ * @return
+ */
+ String getIdentificationType();
+
+
+ /**
+ * Get the identityLink for the authenticated user
+ *
+ * @return IDL, or NULL if no IDL is available
+ */
+ IIdentityLink getIdentityLink();
+
+ /**
+ * Return LoA for this user authentication
+ *
+ * @return eIDAS LoA URI
+ */
+ public String getEIDASQAALevel();
+
+
+ /**
+ * Indicates that the user is a foreigner
+ *
+ * @return true if the user is foreigner, otherwise false
+ */
+ boolean isForeigner();
+
+ /**
+ * Code of the citizen country of the authenticated user
+ *
+ * @return
+ */
+ String getCiticenCountryCode();
+
+
+ /**
+ * Indicate that the authentication was done by using an active single sign-on session
+ *
+ * @return true if it an SSO session was used, otherwise false
+ */
+ boolean isSsoSession();
+
+ /**
+ * Date, up to which the SSO that was used for authentication is valid to
+ *
+ * @return
+ */
+ Date getSsoSessionValidTo();
+
+
+ /**
+ * SessionIndex, if it was an reauthentication on a service provider by using the same SSO session
+ *
+ * @return
+ */
+ String getSessionIndex();
+
+ /**
+ * SAML2 NameID for the user
+ *
+ * @return
+ */
+ String getNameID();
+
+ /**
+ * Format of the SAML2 NameID
+ *
+ * @return
+ */
+ String getNameIDFormat();
+
+
+ /**
+ * Get generic information for this authenticated user
+ *
+ * @param key Identifier for the generic data
+ * @param clazz Type of the generic data
+ * @return return the generic data of specific type, otherwise null
+ */
+ public <T> T getGenericData(String key, final Class<T> clazz);
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAuthenticationDataBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAuthenticationDataBuilder.java
new file mode 100644
index 00000000..4bdefb06
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IAuthenticationDataBuilder.java
@@ -0,0 +1,14 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException;
+
+public interface IAuthenticationDataBuilder {
+
+ IAuthData buildAuthenticationData(IRequest pendingReq) throws EAAFAuthenticationException;
+
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IConfiguration.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IConfiguration.java
new file mode 100644
index 00000000..6aac90f8
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IConfiguration.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.Map;
+import java.util.Properties;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+
+public interface IConfiguration {
+
+ public static final String CONFIG_PROPS_AUTH_DEFAULT_COUNTRYCODE = "configuration.auth.default.countrycode";
+
+ /**
+ * Get a configuration value from file based configuration
+ *
+ * @param key configuration key
+ * @return configuration value or null if it is not found
+ */
+ public String getBasicConfiguration(final String key);
+
+
+ /**
+ * Get a configuration value from file based configuration
+ *
+ * @param key configuration key
+ * @param defaultValue Default value if no value with this key is found
+ * @return configuration value
+ */
+ public String getBasicConfiguration(final String key, final String defaultValue);
+
+ /**
+ * Get a set of configuration values from file based configuration that starts with this prefix
+ * <br><br>
+ * <b>Important:</b> The configuration values must be of type String!
+ *
+ * @param prefix Prefix of the configuration key
+ * @return Map<String, String> without prefix, but never null
+ */
+ public Map<String, String> getBasicMOAIDConfigurationWithPrefix(final String prefix);
+
+
+ /**
+ * Get a boolean value from basic MOA-ID configuration file
+ *
+ * @param key Configuration key
+ * @param defaultValue Default result
+ * @return returns the value of the configuration key, or the default value if the key is not set
+ */
+ public boolean getBasicMOAIDConfigurationBoolean(String key, boolean defaultValue);
+
+ /**
+ * Get a configuration entry for a specific Service Provider
+ *
+ * @param uniqueID Unique identifier of the Service Provider
+ * @return
+ * @throws EAAFConfigurationException
+ */
+ public ISPConfiguration getServiceProviderConfiguration(final String uniqueID) throws EAAFConfigurationException;
+
+
+ /**
+ * Get a configuration entry for a specific Service Provider that is decorated by a Object
+ *
+ * @param spIdentifier EntityID of a Service Provider
+ * @param decorator Decorator that should be used to decorate the result.
+ * This decorator has to be implement or extend the {@link ISPConfiguration} interface
+ * @return
+ * @throws EAAFConfigurationException
+ */
+ public <T> T getServiceProviderConfiguration(String spIdentifier, final Class<T> decorator) throws EAAFConfigurationException;
+
+ /**
+ * Get the full configuration properties object
+ *
+ * @return
+ */
+ public Properties getFullConfigurationProperties();
+
+ /**
+ * Get the root directory of the configuration folder
+ *
+ * @return
+ */
+ public URI getConfigurationRootDirectory();
+
+
+ /**
+ * Get the path to EAAFCore configuration that is internally used
+ *
+ * @return
+ */
+ public URI getConfigurationFilePath();
+
+
+ /**
+ * Validate a URL if it it is allowed by configuration.
+ *
+ * @param authReqUrl URL for validation
+ * @return URL of the application context if the authReqUrl was valid, otherwise null
+ */
+ public String validateIDPURL(URL authReqUrl) throws EAAFException;
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IModulInfo.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IModulInfo.java
new file mode 100644
index 00000000..03a761f2
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IModulInfo.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ *******************************************************************************/
+/*******************************************************************************
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+
+/**
+ * Basic interface of an authentication protocol implementation on IDP side
+ *
+ * @author tlenz
+ *
+ */
+public interface IModulInfo {
+
+ /**
+ * Name of this IDP authentication module
+ *
+ * @return
+ */
+ public String getName();
+
+ /**
+ * Authentication protocol identifier for this module
+ *
+ * @return
+ */
+ public String getAuthProtocolIdentifier();
+
+ /**
+ * Generates a protocol specific error message
+ *
+ *
+ * @param e Exception that contains the error message
+ * @param request httpRequest object from servlet container
+ * @param response httpResponse object from servlet container
+ * @param protocolRequest incoming protocol request
+ * @return return <i>true</i> if a protocol specific error message was generated, otherwise <i>false</i>
+ * @throws Throwable
+ */
+ public boolean generateErrorMessage(Throwable e,
+ HttpServletRequest request, HttpServletResponse response,
+ IRequest protocolRequest) throws Throwable;
+
+ /**
+ * additional validation of a incoming authentication request
+ *
+ * @param request httpRequest object from servlet container
+ * @param response httpResponse object from servlet container
+ * @param pending incoming protocol request
+ * @return return <i>true</i> if the incoming request is valid, otherwise <i>false</i>
+ */
+ public boolean validate(HttpServletRequest request,
+ HttpServletResponse response, IRequest pending);
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IPVPAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IPVPAttributeBuilder.java
new file mode 100644
index 00000000..33693647
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/IPVPAttributeBuilder.java
@@ -0,0 +1,9 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp;
+
+import at.gv.egiz.eaaf.core.api.data.PVPAttributeDefinitions;
+
+public interface IPVPAttributeBuilder extends PVPAttributeDefinitions, IAttributeBuilder {
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/ISPConfiguration.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/ISPConfiguration.java
new file mode 100644
index 00000000..82e4bd1e
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/ISPConfiguration.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+
+public interface ISPConfiguration extends Serializable {
+
+ public static final String CONFIG_KEY_RESTRICTIONS_BASEID_INTERNAL = "configuration.restrictions.baseID.idpProcessing";
+ public static final String CONFIG_KEY_RESTRICTIONS_BASEID_TRANSMISSION = "configuration.restrictions.baseID.spTransmission";
+
+ /**
+ * Get the full key/value configuration for this Service Provider
+ *
+ * @return an unmodifiable map of key/value pairs
+ */
+ public Map<String, String> getFullConfiguration();
+
+ /**
+ * Get a configuration value from Service Provider key/value configuration
+ *
+ * @param key The key identifier of a configuration value
+ * @return The configuration value {String} or null if the key does not exist
+ */
+ public String getConfigurationValue(String key);
+
+ /**
+ * Get a configuration value from Service Provider key/value configuration
+ *
+ * @param key The key identifier of a configuration value
+ * @param defaultValue Default value if key does not exist
+ * @return The configuration value {String} or defaultValue if the key does not exist
+ */
+ public String getConfigurationValue(String key, String defaultValue);
+
+ /**
+ * Get a boolean configuration value from Service Provider key/value configuration
+ *
+ * @param key The key identifier of a configuration value
+ * @return true / false, or null if the key does not exist
+ */
+ public Boolean isConfigurationValue(String key);
+
+
+ /**
+ * Get a boolean configuration value from Service Provider key/value configuration
+ *
+ * @param key The key identifier of a configuration value
+ * @param defaultValue Default value if key does not exist
+ * @return true / false, or defaultValue if the key does not exist
+ */
+ public boolean isConfigurationValue(String key, boolean defaultValue);
+
+ /**
+ * Check if a configuration key is available in this Service Provider configuration
+ *
+ * @param key The key identifier of a configuration value
+ * @return true if the configuration key exists, otherwise false
+ */
+ boolean containsConfigurationKey(String key);
+
+ /**
+ * Return the unique identifier of this Service Provider
+ *
+ * @return
+ */
+ public String getUniqueIdentifier();
+
+ /**
+ * Return the unique identifier of this Service Provider
+ *
+ * @return
+ */
+ public String getFriendlyName();
+
+ /**
+ * Indicates if this service provider has private area restrictions that disallow baseId processing in general
+ * *
+ * @return true if there is a restriction, otherwise false
+ */
+ public boolean hasBaseIdInternalProcessingRestriction();
+
+
+ /**
+ * Indicates if this service provider has private area restrictions that disallow baseId transfer to SP
+ *
+ * @return true if there is a restriction, otherwise false
+ */
+ public boolean hasBaseIdTransferRestriction();
+
+ /**
+ * Get the {@link List} of identifier's that indicates no baseID processing restriction exists.<br>
+ * This list can be configured by key: "configuration.restrictions.baseID.idpProcessing"
+ *
+ * @return
+ */
+ public List<String> getTargetsWithNoBaseIdInternalProcessingRestriction();
+
+ /**
+ * Get the {@link List} of identifier's that indicates no baseID transfer restriction exists.<br>
+ * This list can be configured by key: "configuration.restrictions.baseID.spTransmission"
+ *
+ * @return
+ */
+ public List<String> getTargetsWithNoBaseIdTransferRestriction();
+
+ /**
+ * Get the minimum eIDAS LoA that is required by this service provider
+ *
+ * {@link EAAFConstants.EIDAS_QAA_LOW}
+ * {@link EAAFConstants.EIDAS_QAA_SUBSTANTIAL}
+ * {@link EAAFConstants.EIDAS_QAA_HIGH}
+ *
+ * @return return eIDAS LoA
+ */
+ public String getMinimumLevelOfAssurence();
+
+ /**
+ * Get the full area-identifier for this service provider to calculate the
+ * area-specific unique person identifier (bPK, wbPK, eIDAS unique identifier, ...).
+ * This identifier always contains the full prefix
+ *
+ * @return area identifier with prefix
+ */
+ public String getAreaSpecificTargetIdentifier();
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/IAuthenticationManager.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/IAuthenticationManager.java
new file mode 100644
index 00000000..82f87f49
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/IAuthenticationManager.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp.auth;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.idp.slo.ISLOInformationContainer;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+
+public interface IAuthenticationManager {
+
+ //TODO
+ public static int EVENT_AUTHENTICATION_PROCESS_FOR_SP = -1;
+ public static int EVENT_AUTHENTICATION_PROCESS_STARTED = -1;
+ public static int EVENT_AUTHENTICATION_PROCESS_FINISHED = -1;
+ public static int EVENT_AUTHENTICATION_PROCESS_ERROR = -1;
+
+
+ /**
+ * Add a request parameter to whitelist. All parameters that are part of the white list are added into {@link ExecutionContext}
+ *
+ * @param httpReqParam http parameter name, but never null
+ */
+ void addParameterNameToWhiteList(String httpReqParam);
+
+ /**
+ * Add a request header to whitelist. All parameters that are part of the white list are added into {@link ExecutionContext}
+ *
+ * @param httpReqParam http header name, but never null
+ */
+ void addHeaderNameToWhiteList(String httpReqParam);
+
+
+ /**
+ * Starts an authentication process for a specific pending request
+ *
+ * @param httpReq http servlet request
+ * @param httpResp http servlet response
+ * @param pendingReq Pending request for that an authentication is required
+ * @return true if the pending request is already authenticated, otherwise false
+ * @throws EAAFException
+ */
+ boolean doAuthentication(HttpServletRequest httpReq, HttpServletResponse httpResp,
+ IRequest pendingReq) throws EAAFException;
+
+ /**
+ * Close an active authenticated session on IDP side
+ *
+ * @param request http servlet request
+ * @param response http servlet response
+ * @param pendingReq ReqPending request for that an authentication session should be closed
+ */
+ void performOnlyIDPLogOut(HttpServletRequest request, HttpServletResponse response, IRequest pendingReq);
+
+
+ /**
+ * Close an active authenticated session on IDP side and get a list authenticated service providers
+ *
+ * @param request http servlet request
+ * @param response http servlet response
+ * @param pendingReq ReqPending request for that an authentication session should be closed
+ * @param internalSSOId internal SSO session identifier
+ * @return A container that contains all active SP sessions
+ * @throws EAAFException
+ */
+ ISLOInformationContainer performSingleLogOut(HttpServletRequest httpReq, HttpServletResponse httpResp, IRequest pendingReq, String internalSSOId) throws EAAFException;
+
+
+} \ No newline at end of file
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/ISSOManager.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/ISSOManager.java
new file mode 100644
index 00000000..9c7a7320
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/ISSOManager.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp.auth;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface;
+import at.gv.egiz.eaaf.core.exceptions.EAAFSSOException;
+
+public interface ISSOManager {
+
+ //TODO
+ public static int EVENT_SSO_SESSION_INVALID = -1;
+ public static int EVENT_SSO_SESSION_VALID = -1;
+
+
+ public static final String PROCESS_ENGINE_SSO_CONSENTS_EVALUATION = "ssoconsentsevaluation";
+ public static final String AUTH_DATA_SSO_SESSIONID = "eaaf_authdata_sso_sessionId";
+
+
+ /**
+ * Check if there is an active and valid SSO session for the current pending request.
+ * <br>
+ * If there is an active SSO session, the pending request will be populated with eID information from SSO session
+ *
+ * @param pendingReq Current incoming pending request
+ * @param httpReq http Servlet request
+ * @param httpResp http Servlet response
+ * @return true if there is a valid SSO session, otherwise false
+ * @throws EAAFSSOException
+ */
+ public boolean checkAndValidateSSOSession(IRequest pendingReq, HttpServletRequest httpReq, HttpServletResponse httpResp) throws EAAFSSOException;
+
+ /**
+ * Populate service provider specific SSO settings
+ *
+ * Check if Single Sign-On is allowed for the current pending request and the requested service provider
+ *
+ * @param pendingReq Current incoming pending request
+ * @param httpReq http Servlet request
+ * @return true if SSO is allowed for this service provider, otherwise false
+ */
+ public void isSSOAllowedForSP(IRequest pendingReq, HttpServletRequest httpReq);
+
+
+ /**
+ * Populate the current pending request with eID information from an existing SSO session
+ *
+ * @param pendingReq pending request that should be populated by SSO session
+ * @throws EAAFSSOException if pending request contains no SSO information or population failed
+ */
+ public void populatePendingRequestWithSSOInformation(IRequest pendingReq) throws EAAFSSOException;
+
+
+ /**
+ * Destroy an active SSO session on IDP site only
+ *
+ * @param httpReq http servlet request
+ * @param httpResp http servlet response
+ * @param pendingReq
+ * @return true if a SSO session was closed successfully, otherwise false
+ * @throws EAAFSSOException in case of an internal processing error
+ */
+ public boolean destroySSOSessionOnIDPOnly(HttpServletRequest httpReq, HttpServletResponse httpResp, IRequest pendingReq) throws EAAFSSOException;
+
+
+
+ // ************************* old ***************************************************
+ String createNewSSOSessionCookie(HttpServletRequest req, HttpServletResponse resp, IRequest pendingReq) throws EAAFSSOException;
+
+
+ void createNewSSOSession(IRequest pendingReq, String newSSOSessionId, SLOInformationInterface sloInformation) throws EAAFSSOException;
+// {
+// internalDBSSOSession = authenticatedSessionStorage.createInternalSSOSession(pendingReq);
+// authenticatedSessionStorage.addSSOInformation(internalDBSSOSession.getSessionID(),
+// newSSOSessionId, sloInformation, pendingReq);
+//
+// }
+
+
+ void updateSSOSession(IRequest pendingReq, String newSSOSessionId, SLOInformationInterface sloInformation) throws EAAFSSOException;
+// {
+// authenticatedSessionStorage.addSSOInformation(moaSession.getSessionID(),
+// newSSOSessionId, sloInformation, pendingReq);
+// }
+
+
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/data/IAuthProcessDataContainer.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/data/IAuthProcessDataContainer.java
new file mode 100644
index 00000000..743c7797
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/data/IAuthProcessDataContainer.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp.auth.data;
+
+import java.util.Date;
+import java.util.Map;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException;
+
+public interface IAuthProcessDataContainer {
+
+ /**
+ * Returns the issuing time of the AUTH-Block SAML assertion.
+ *
+ * @return The issuing time of the AUTH-Block SAML assertion.
+ */
+ String getIssueInstant();
+
+ /**
+ * Sets the issuing time of the AUTH-Block SAML assertion.
+ *
+ * @param issueInstant
+ * The issueInstant to set.
+ */
+ void setIssueInstant(String issueInstant);
+
+ /**
+ * Indicate if the authentication process is finished
+ *
+ * @return
+ */
+ boolean isAuthenticated();
+
+ /**
+ * Mark the authentication as authenticated, which means that the authenication process is completed
+ *
+ * @param authenticated
+ */
+ void setAuthenticated(boolean authenticated);
+
+ /**
+ * Returns the identityLink.
+ *
+ * @return IdentityLink
+ */
+ IIdentityLink getIdentityLink();
+
+ /**
+ * Sets the identityLink.
+ *
+ * @param identityLink
+ * The identityLink to set
+ */
+ void setIdentityLink(IIdentityLink identityLink);
+
+
+ /**
+ * Indicate that mandates was used in this auth. process
+ *
+ * @return
+ */
+ boolean isMandateUsed();
+
+ /**
+ * Mark that mandates was used in this auth. process
+ *
+ * @param useMandates
+ */
+ void setUseMandates(boolean useMandates);
+
+ /**
+ * Indicate that the auth. process was performed by a foreigner
+ *
+ * @return
+ */
+ boolean isForeigner();
+
+ /**
+ * Mark that the auth. process was done by a foreigner
+ *
+ * @param isForeigner
+ */
+ void setForeigner(boolean isForeigner);
+
+ /**
+ * Indicate that the auth. process was performed by an official representatives
+ *
+ * @return is official representatives
+ */
+ boolean isOW();
+
+ /**
+ * Mark that the auth. process was done by an official representatives
+ *
+ */
+ void setOW(boolean isOW);
+
+ /**
+ * eIDAS QAA level
+ *
+ * @return the qAALevel
+ */
+ String getQAALevel();
+
+ /**
+ * set QAA level in eIDAS form
+ *
+ * @param qAALevel the qAALevel to set
+ */
+ void setQAALevel(String qAALevel);
+
+ /**
+ * @return the sessionCreated
+ */
+ Date getSessionCreated();
+
+ Map<String, Object> getGenericSessionDataStorage();
+
+ /**
+ * Returns a generic session-data object with is stored with a specific identifier
+ *
+ * @param key The specific identifier of the session-data object
+ * @return The session-data object or null if no data is found with this key
+ */
+ Object getGenericDataFromSession(String key);
+
+ /**
+ * Returns a generic session-data object with is stored with a specific identifier
+ *
+ * @param key The specific identifier of the session-data object
+ * @param clazz The class type which is stored with this key
+ * @return The session-data object or null if no data is found with this key
+ */
+ <T> T getGenericDataFromSession(String key, Class<T> clazz);
+
+ /**
+ * Store a generic data-object to session with a specific identifier
+ *
+ * @param key Identifier for this data-object
+ * @param object Generic data-object which should be stored. This data-object had to be implement the 'java.io.Serializable' interface
+ * @throws EAAFStorageException Error message if the data-object can not stored to generic session-data storage
+ */
+ void setGenericDataToSession(String key, Object object) throws EAAFStorageException;
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/data/IIdentityLink.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/data/IIdentityLink.java
new file mode 100644
index 00000000..ca1f145d
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/data/IIdentityLink.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp.auth.data;
+
+import java.io.IOException;
+import java.security.PublicKey;
+
+import javax.xml.transform.TransformerException;
+
+import org.w3c.dom.Element;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface IIdentityLink {
+
+ /**
+ * Returns the dateOfBirth.
+ * @return Calendar
+ */
+ String getDateOfBirth();
+
+ /**
+ * Returns the familyName.
+ * @return String
+ */
+ String getFamilyName();
+
+ /**
+ * Returns the givenName.
+ * @return String
+ */
+ String getGivenName();
+
+ /**
+ * Returns the name.
+ * @return The name.
+ */
+ String getName();
+
+ /**
+ * Returns the identificationValue.
+ * <code>"identificationValue"</code> is the translation of <code>"Stammzahl"</code>.
+ * @return String
+ */
+ String getIdentificationValue();
+
+ /**
+ * Returns the identificationType.
+ * <code>"identificationType"</code> type of the identificationValue in the IdentityLink.
+ * @return String
+ */
+ String getIdentificationType();
+
+ /**
+ * Sets the dateOfBirth.
+ * @param dateOfBirth The dateOfBirth to set
+ */
+ void setDateOfBirth(String dateOfBirth);
+
+ /**
+ * Sets the familyName.
+ * @param familyName The familyName to set
+ */
+ void setFamilyName(String familyName);
+
+ /**
+ * Sets the givenName.
+ * @param givenName The givenName to set
+ */
+ void setGivenName(String givenName);
+
+ /**
+ * Sets the identificationValue.
+ * <code>"identificationValue"</code> is the translation of <code>"Stammzahl"</code>.
+ * @param identificationValue The identificationValue to set
+ */
+ void setIdentificationValue(String identificationValue);
+
+ /**
+ * Sets the Type of the identificationValue.
+ * @param identificationType The type of identificationValue to set
+ */
+ void setIdentificationType(String identificationType);
+
+ /**
+ * Returns the samlAssertion.
+ * @return Element
+ */
+ Element getSamlAssertion();
+
+ /**
+ * Returns the samlAssertion.
+ * @return Element
+ */
+ String getSerializedSamlAssertion();
+
+ /**
+ * Sets the samlAssertion and the serializedSamlAssertion.
+ * @param samlAssertion The samlAssertion to set
+ */
+ void setSamlAssertion(Element samlAssertion) throws TransformerException, IOException;
+
+ /**
+ * Returns the dsigReferenceTransforms.
+ * @return Element[]
+ */
+ Element[] getDsigReferenceTransforms();
+
+ /**
+ * Sets the dsigReferenceTransforms.
+ * @param dsigReferenceTransforms The dsigReferenceTransforms to set
+ */
+ void setDsigReferenceTransforms(Element[] dsigReferenceTransforms);
+
+ /**
+ * Returns the publicKey.
+ * @return PublicKey[]
+ */
+ PublicKey[] getPublicKey();
+
+ /**
+ * Sets the publicKey.
+ * @param publicKey The publicKey to set
+ */
+ void setPublicKey(PublicKey[] publicKey);
+
+ /**
+ * Returns the prPerson.
+ * @return Element
+ */
+ Element getPrPerson();
+
+ /**
+ * Sets the prPerson.
+ * @param prPerson The prPerson to set
+ */
+ void setPrPerson(Element prPerson);
+
+ /**
+ * Returns the issuing time of the identity link SAML assertion.
+ *
+ * @return The issuing time of the identity link SAML assertion.
+ */
+ String getIssueInstant();
+
+ /**
+ * Sets the issuing time of the identity link SAML assertion.
+ *
+ * @param issueInstant The issueInstant to set.
+ */
+ void setIssueInstant(String issueInstant);
+
+} \ No newline at end of file
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/modules/AuthModule.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/modules/AuthModule.java
new file mode 100644
index 00000000..d8f15aff
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/auth/modules/AuthModule.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp.auth.modules;
+
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessDefinition;
+
+/**
+ * Provides metadata of a certain module. Uses for module discovery and process selection.
+ */
+public interface AuthModule {
+
+ /**
+ * Returns the priority of the module. The priority defines the order of the respective module within the chain of
+ * discovered modules. Higher priorized modules are asked before lower priorized modules for a process that they can
+ * handle.
+ * <p/>
+ * Internal default modules are priorized neutral ({@code 0}. Use a higher priority ({@code 1...Integer.MAX_VALUE})
+ * in order to have your module(s) priorized or a lower priority ({@code Integer.MIN_VALUE...-1}) in order to put
+ * your modules behind default modules.
+ *
+ * @return the priority of the module.
+ */
+ int getPriority();
+
+ /**
+ * Selects a process (description), referenced by its unique id, which is able to perform authentication with the
+ * given {@link ExecutionContext}. Returns {@code null} if no appropriate process (description) was available within
+ * this module.
+ *
+ * @param context
+ * an ExecutionContext for a process.
+ * @return the process-ID of a process which is able to work with the given ExecutionContext, or {@code null}.
+ */
+ String selectProcess(ExecutionContext context);
+
+ /**
+ * Returns the an Array of {@link ProcessDefinition}s of the processes included in this module.
+ *
+ * @return an array of resource uris of the processes included in this module.
+ */
+ String[] getProcessDefinitions();
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExecutionContext.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExecutionContext.java
new file mode 100644
index 00000000..e5e2011b
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExecutionContext.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp.process;
+
+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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExpressionEvaluationContext.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExpressionEvaluationContext.java
new file mode 100644
index 00000000..6e976422
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExpressionEvaluationContext.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp.process;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import at.gv.egiz.eaaf.core.impl.idp.process.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExpressionEvaluator.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExpressionEvaluator.java
new file mode 100644
index 00000000..eda6b3cb
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ExpressionEvaluator.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp.process;
+
+/**
+ * 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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ProcessEngine.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ProcessEngine.java
new file mode 100644
index 00000000..523eb8dc
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ProcessEngine.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp.process;
+
+
+import java.io.InputStream;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.exceptions.ProcessExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.process.ProcessDefinitionParserException;
+import at.gv.egiz.eaaf.core.impl.idp.process.ProcessInstance;
+import at.gv.egiz.eaaf.core.impl.idp.process.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.
+ * @return The process definition's identifier.
+ */
+ String registerProcessDefinition(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException;
+
+ /**
+ * Creates a process instance according to the referenced process definition, persists it into the database and returns it identifier.
+ * <p/>
+ * Note that the method returns the identifier of 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(String)} and
+ * {@link #signal(String)} for further information).
+ *
+ * @param processDefinitionId
+ * The identifier of the respective process definition.
+ * @param executionContext The execution context (may be {@code null}).
+ * @return The id of 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.
+ */
+ String createProcessInstance(String processDefinitionId, ExecutionContext executionContext) throws ProcessExecutionException;
+
+ /**
+ * Creates a process instance according to the referenced process definition, persists it into the database and returns it identifier.
+ * <p/>
+ * Note that the method returns the identifier of 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(String)} and
+ * {@link #signal(String)} for further information).
+ *
+ * @param processDefinitionId
+ * The identifier of the respective process definition.
+ * @return The id of 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.
+ */
+ String createProcessInstance(String processDefinitionId) throws ProcessExecutionException;
+
+
+ /**
+ * Delete a process instance
+ *
+ * @param processInstanceId
+ * The identifier of the respective process.
+ * @throws ProcessExecutionException
+ * Thrown in case of error, e.g. when a {@code processInstanceId} is referenced that does not exist.
+ */
+ void deleteProcessInstance(String processInstanceId) 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.
+ * @throws RuntimeException
+ * In case the process instance could not be retrieved from persistence.
+ */
+ ProcessInstance getProcessInstance(String processInstanceId);
+
+ /**
+ * Starts the process using the given {@code pendingReq}.
+ *
+ * @param pendingReq
+ * The protocol request for which a process should be started.
+ * @throws ProcessExecutionException
+ * Thrown in case of error.
+ */
+ void start(IRequest pendingReq) throws ProcessExecutionException;
+
+
+ /**
+ * Resumes process execution after an asynchronous task has been executed.
+ *
+ * @param pendingReq
+ * The process instance id.
+ * @throws ProcessExecutionException
+ * Thrown in case of error.
+ */
+ void signal(IRequest pendingReq) throws ProcessExecutionException;
+
+} \ No newline at end of file
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ProcessInstanceStoreDAO.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ProcessInstanceStoreDAO.java
new file mode 100644
index 00000000..1242620b
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/ProcessInstanceStoreDAO.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp.process;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException;
+import at.gv.egiz.eaaf.core.impl.idp.process.ProcessInstance;
+import at.gv.egiz.eaaf.core.impl.idp.process.dao.ProcessInstanceStore;
+
+public interface ProcessInstanceStoreDAO {
+
+ /**
+ * Stores a {@link ProcessInstance} defined by {@code pIStore} in the
+ * database.
+ *
+ * @param pIStore
+ * the {@link ProcessInstanceStore} to persist.
+ * @throws EAAFStorageException
+ * is thrown if a problem occurs while accessing the database.
+ */
+ void saveOrUpdate(ProcessInstanceStore pIStore) throws EAAFException;
+
+ /**
+ * Returns a {@link ProcessInstanceStore}, defined by
+ * {@code processInstanceID} from the database, or {@code null} if the
+ * object could not be found.
+ *
+ * @param processInstanceId
+ * the id of the {@code ProcessInstanceStore} to retrieve.
+ * @return a ProcessInstanceStore, or {@code null}.
+ * @throws EAAFStorageException
+ * is thrown if a problem occurs while accessing the database.
+ */
+ ProcessInstanceStore load(String processInstanceId) throws EAAFException;
+
+ /**
+ * Deletes the {@link ProcessInstance} corresponding with the
+ * {@code processInstanceId}.
+ *
+ * @param processInstanceId
+ * the id of the {@code ProcessInstance} to be deleted.
+ * @throws EAAFStorageException
+ * is thrown if a problem occurs while accessing the database.
+ */
+ void remove(String processInstanceId) throws EAAFException;
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/Task.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/Task.java
new file mode 100644
index 00000000..ff28b714
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/process/Task.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.idp.process;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+
+
+/**
+ * Represents a single task to be performed upon process execution.
+ *
+ * @author tknall
+ *
+ */
+public interface Task {
+
+ /**
+ * Executes this task.
+ * @param pendingReq
+ * Provides the current processed protocol request
+ * @param executionContext
+ * Provides execution related information.
+ * @return The pending-request object, because Process-management works recursive
+ * @throws Exception An exception upon task execution.
+ */
+ IRequest execute(IRequest pendingReq, ExecutionContext executionContext) throws TaskExecutionException;
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/slo/ISLOInformationContainer.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/slo/ISLOInformationContainer.java
new file mode 100644
index 00000000..b5798f7b
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/slo/ISLOInformationContainer.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ *******************************************************************************/
+/**
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egiz.eaaf.core.api.idp.slo;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface ISLOInformationContainer {
+
+ boolean hasFrontChannelOA();
+
+ Set<Entry<String, SLOInformationInterface>> getFrontChannelOASessionDescriptions();
+
+ void removeFrontChannelOA(String oaID);
+
+ Iterator<String> getNextBackChannelOA();
+
+ SLOInformationInterface getBackChannelOASessionDescripten(String oaID);
+
+ void removeBackChannelOA(String oaID);
+
+ /**
+ * @return the sloRequest
+ */
+ IRequest getSloRequest();
+
+ /**
+ * @param sloRequest the sloRequest to set
+ */
+ void setSloRequest(IRequest sloRequest);
+
+ /**
+ * @return the sloFailedOAs
+ */
+ List<String> getSloFailedOAs();
+
+ void putFailedOA(String oaID);
+
+ public String getTransactionID();
+
+ public String getSessionID();
+} \ No newline at end of file
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/slo/SLOInformationInterface.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/slo/SLOInformationInterface.java
new file mode 100644
index 00000000..bd630c0a
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/idp/slo/SLOInformationInterface.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ *******************************************************************************/
+/**
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egiz.eaaf.core.api.idp.slo;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface SLOInformationInterface{
+
+
+ /**
+ * get AssertionID which was used for Service Provider Single LogOut request
+ *
+ * @return
+ * SessionID (SessionIndex in case of SAML2)
+ */
+ public String getSessionIndex();
+
+ /**
+ * get user identifier which was used
+ *
+ * @return
+ * bPK / wbPK (nameID in case of SAML2)
+ */
+ public String getUserNameIdentifier();
+
+
+ /**
+ * get protocol type which was used for authentication
+ *
+ * @return
+ * return authentication protocol type
+ */
+ public String getProtocolType();
+
+ /**
+ * @return
+ */
+ public String getUserNameIDFormat();
+
+ /**
+ * Get the unique entityID of this Service-Provider
+ *
+ * @return unique identifier, but never null
+ */
+ public String getSpEntityID();
+
+ public String getAuthURL();
+
+ public String getServiceURL();
+
+ public String getBinding();
+
+ public void setUserNameIdentifier(String subjectNameId);
+
+ public void setNameIDFormat(String format);
+
+ public void setSessionIndex(String sessionIndex);
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/logging/IRevisionLogger.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/logging/IRevisionLogger.java
new file mode 100644
index 00000000..ab269694
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/logging/IRevisionLogger.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.logging;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+
+public interface IRevisionLogger {
+
+
+ //TODO:
+ public static final int AUTHPROTOCOL_TYPE = 3000;
+
+ void logEvent(ISPConfiguration oaConfig, int eventCode, String message);
+
+ void logEvent(IRequest pendingRequest, int eventCode);
+
+ void logEvent(IRequest pendingRequest, int eventCode, String message);
+
+ /**
+ * @param sessionCreated
+ * @param uniqueSessionIdentifier
+ */
+ void logEvent(int eventCode, String message);
+
+ /**
+ * @param sessionCreated
+ * @param uniqueSessionIdentifier
+ */
+ void logEvent(String sessionID, String transactionID, int eventCode, String message);
+
+ /**
+ * @param sessionCreated
+ * @param uniqueSessionIdentifier
+ */
+ void logEvent(String sessionID, String transactionID, int eventCode);
+
+} \ No newline at end of file
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/logging/IStatisticLogger.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/logging/IStatisticLogger.java
new file mode 100644
index 00000000..7774fb22
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/logging/IStatisticLogger.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.logging;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+
+
+
+public interface IStatisticLogger {
+
+ public void logSuccessOperation(IRequest protocolRequest, IAuthData authData, boolean isSSOSession);
+
+ public void logErrorOperation(Throwable throwable);
+
+ public void logErrorOperation(Throwable throwable, IRequest errorRequest);
+
+ public void internalTesting() throws Exception;
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/storage/ITransactionStorage.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/storage/ITransactionStorage.java
new file mode 100644
index 00000000..41c55148
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/storage/ITransactionStorage.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.api.storage;
+
+import java.util.Date;
+import java.util.List;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException;
+
+/**
+ * @author tlenz
+ *
+ */
+public interface ITransactionStorage {
+
+ /**
+ * Check if transaction storage contains a data object with a specific key
+ *
+ * @param key Key, which identifies a data object
+ * @return true if key is found, otherwise false
+ */
+ public boolean containsKey(String key);
+
+ /**
+ * Store a data object with a key to transaction storage
+ *
+ * @param key Id which identifiers the data object
+ * @param value Data object which should be stored.
+ * This data must implement the <code>java.io.Serializable</code> interface
+ * @param timeout_ms Defines the period of time a data object is kept within the storage
+ * @throws EAAFStorageException In case of store operation failed
+ */
+ public void put(String key, Object value, int timeout_ms) throws EAAFException;
+
+ /**
+ * Get a data object from transaction storage
+ *
+ * @param key key Id which identifiers the data object
+ * @return The transaction-data object, or null
+ * @throws EAAFStorageException In case of load operation failed
+ */
+ public Object get(String key) throws EAAFException;
+
+ /**
+ * Get a data object from transaction storage
+ *
+ * @param key Id which identifiers the data object
+ * @param clazz The class type which is stored with this key
+ * @return The transaction-data object from type class, or null
+ * @throws EAAFStorageException In case of load operation failed
+ */
+ public <T> T get(String key, final Class<T> clazz) throws EAAFException;
+
+ /**
+ * Get a data object from transaction storage
+ *
+ * @param key Id which identifiers the data object
+ * @param clazz The class type which is stored with this key
+ * @param Data-object timeout in [ms]
+ * @return The transaction-data object from type class, or null
+ * @throws EAAFStorageException In case of load operation failed
+ */
+ public <T> T get(String key, final Class<T> clazz, long dataTimeOut) throws EAAFException;
+
+
+ /**
+ * Change the key of a data object and store it under the new key
+ *
+ * @param oldKey Old key of the data object
+ * @param newKey New key, which should be used to store the data object
+ * @param value Data object which should be stored
+ * @throws EAAFStorageException In case of store operation failed
+ */
+ public void changeKey(String oldKey, String newKey, Object value) throws EAAFException;
+
+ /**
+ * Remove a data object from transaction storage
+ *
+ * @param key Id which identifiers the data object
+ */
+ public void remove(String key);
+
+ /**
+ * Get all entries for Clean-up the transaction storage
+ *
+ * @param now Current time
+ * @param dataTimeOut Data-object timeout in [ms]
+ * @return List of entry-keys which as a timeout
+ */
+ public List<String> clean(Date now, long dataTimeOut);
+
+
+ /**
+ * Get a raw object from storage by using this key
+ *
+ * @param key
+ * @return
+ * @throws EAAFException
+ */
+ public Object getRaw(String key) throws EAAFException;
+
+
+ /**
+ * Set a raw object to storage
+ *
+ * @param key
+ * @param element
+ * @throws EAAFException
+ */
+ public void putRaw(String key, Object element) throws EAAFException;
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AttributeBuilderException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AttributeBuilderException.java
new file mode 100644
index 00000000..7e5373be
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AttributeBuilderException.java
@@ -0,0 +1,13 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class AttributeBuilderException extends EAAFIDPException {
+
+ private static final long serialVersionUID = 1L;
+
+ public AttributeBuilderException(String msg) {
+ super(msg);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AttributePolicyException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AttributePolicyException.java
new file mode 100644
index 00000000..7f484feb
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AttributePolicyException.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class AttributePolicyException extends AttributeBuilderException {
+
+ private static final long serialVersionUID = 1L;
+
+ private String attributeName;
+
+ public AttributePolicyException(String attributeName) {
+ super("Attribute " + attributeName + " is restricted by IDP policy.");
+ this.attributeName = attributeName;
+ }
+
+ public String getAttributeName() {
+ return attributeName;
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AuthnRequestValidatorException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AuthnRequestValidatorException.java
new file mode 100644
index 00000000..c416b8e0
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/AuthnRequestValidatorException.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+
+/**
+ * @author tlenz
+ *
+ */
+public class AuthnRequestValidatorException extends EAAFProtocolException {
+
+ private IRequest errorRequest = null;
+ protected String statusCodeValue;
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 4939651000658508576L;
+
+ /**
+ * @param messageId
+ * @param parameters
+ */
+ public AuthnRequestValidatorException(String internalMsgId, Object[] params, String msg) {
+ super(internalMsgId, params, msg);
+
+ }
+
+ public AuthnRequestValidatorException(String internalMsgId, Object[] params, String msg, IRequest errorRequest) {
+ super(internalMsgId, params, msg);
+ this.errorRequest = errorRequest;
+
+ }
+
+ /**
+ * @return the errorRequest
+ */
+ public IRequest getErrorRequest() {
+ return errorRequest;
+ }
+
+ public String getStatusCodeValue() {
+ return statusCodeValue;
+ }
+
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFAuthenticationException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFAuthenticationException.java
new file mode 100644
index 00000000..87176194
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFAuthenticationException.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class EAAFAuthenticationException extends EAAFException {
+
+
+
+ private static final long serialVersionUID = -4793625336456467005L;
+
+ public EAAFAuthenticationException(String internalMsgId, Object[] params, String msg) {
+ super(internalMsgId, params, msg);
+
+ }
+
+ public EAAFAuthenticationException(String internalMsgId, Object[] params, String msg, Throwable e) {
+ super(internalMsgId, params, msg, e);
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFBuilderException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFBuilderException.java
new file mode 100644
index 00000000..b58d8b7f
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFBuilderException.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class EAAFBuilderException extends EAAFException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public EAAFBuilderException(String errorId, Object[] params, String msg) {
+ super(errorId, params, msg);
+ }
+
+ public EAAFBuilderException(String errorId, Object[] objects, String message, Exception ex) {
+ super(errorId, objects, message, ex);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFConfigurationException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFConfigurationException.java
new file mode 100644
index 00000000..9615d8fd
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFConfigurationException.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class EAAFConfigurationException extends EAAFException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public EAAFConfigurationException(String msg) {
+ super(msg);
+ }
+
+ public EAAFConfigurationException(String msg, Throwable e) {
+ super(msg, e);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFException.java
new file mode 100644
index 00000000..c72bc130
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFException.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class EAAFException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ private String errorId = null;
+ private Object[] params = null;
+
+ public EAAFException(String msg) {
+ super(msg);
+
+ }
+
+ public EAAFException(String msg, Throwable e) {
+ super(msg, e);
+
+ }
+
+ public EAAFException(String errorId, Object[] params, String msg) {
+ super(msg);
+ this.errorId = errorId;
+ this.params = params;
+
+ }
+
+ public EAAFException(String errorId, Object[] params, String msg, Throwable e) {
+ super(msg, e);
+ this.errorId = errorId;
+ this.params = params;
+
+ }
+
+ public String getErrorId() {
+ return this.errorId;
+
+ }
+
+ public Object[] getParams() {
+ return this.params;
+
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFIDPException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFIDPException.java
new file mode 100644
index 00000000..e9cdccb8
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFIDPException.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class EAAFIDPException extends EAAFException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public EAAFIDPException(String msg) {
+ super(msg);
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFIllegalStateException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFIllegalStateException.java
new file mode 100644
index 00000000..65934015
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFIllegalStateException.java
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+import at.gv.egiz.eaaf.core.api.IStatusMessager;
+
+public class EAAFIllegalStateException extends EAAFException {
+ private static final long serialVersionUID = 261484121729891927L;
+
+ public EAAFIllegalStateException(Object[] params, String msg) {
+ super(IStatusMessager.CODES_INTERNAL_ILLEGAL_STATE, params, msg);
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFParserException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFParserException.java
new file mode 100644
index 00000000..de6e91ae
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFParserException.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class EAAFParserException extends EAAFException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public EAAFParserException(String errorId, Object[] params, String msg) {
+ super(errorId, params, msg);
+ }
+
+ public EAAFParserException(String errorId, Object[] objects, String message, Throwable ex) {
+ super(errorId, objects, message, ex);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFProtocolException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFProtocolException.java
new file mode 100644
index 00000000..f3ed4bb7
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFProtocolException.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class EAAFProtocolException extends EAAFException {
+
+ private static final long serialVersionUID = 7982298114399440473L;
+
+ public EAAFProtocolException(String msg) {
+ super(msg);
+
+ }
+
+ public EAAFProtocolException(String msg, Throwable e) {
+ super(msg, e);
+ }
+
+ public EAAFProtocolException(String errorId, Object[] params, String msg) {
+ super(errorId, params, msg);
+
+ }
+
+ public EAAFProtocolException(String errorId, Object[] params, String msg, Throwable e) {
+ super(errorId, params, msg, e);
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFSSOException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFSSOException.java
new file mode 100644
index 00000000..396fee05
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFSSOException.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class EAAFSSOException extends EAAFException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -5942886204347860148L;
+
+ public EAAFSSOException(String errorId, Object[] params, String msg, Throwable e) {
+ super(errorId, params, msg, e);
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFStorageException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFStorageException.java
new file mode 100644
index 00000000..7d0acef8
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/EAAFStorageException.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class EAAFStorageException extends EAAFException {
+
+ private static final long serialVersionUID = 1L;
+
+ public EAAFStorageException(String msg) {
+ super(msg);
+ }
+
+ public EAAFStorageException(String msg, Throwable e) {
+ super(msg, e);
+ }
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/GUIBuildException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/GUIBuildException.java
new file mode 100644
index 00000000..6043d559
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/GUIBuildException.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+/**
+ * @author tlenz
+ *
+ */
+public class GUIBuildException extends Exception {
+
+ private static final long serialVersionUID = -278663750102498205L;
+
+ /**
+ * @param string
+ */
+ public GUIBuildException(String msg) {
+ super(msg);
+
+ }
+
+ public GUIBuildException(String msg, Throwable e) {
+ super(msg, e);
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/InvalidDateFormatAttributeException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/InvalidDateFormatAttributeException.java
new file mode 100644
index 00000000..2afc0720
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/InvalidDateFormatAttributeException.java
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class InvalidDateFormatAttributeException extends AttributeBuilderException {
+
+ private static final long serialVersionUID = 1L;
+
+ public InvalidDateFormatAttributeException() {
+ super("Date format is invalid.");
+ }
+
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/InvalidProtocolRequestException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/InvalidProtocolRequestException.java
new file mode 100644
index 00000000..d7b0933b
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/InvalidProtocolRequestException.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+/**
+ * @author tlenz
+ *
+ */
+public class InvalidProtocolRequestException extends EAAFProtocolException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7866198705324084601L;
+
+ public InvalidProtocolRequestException(String internalMsgId, Object[] params, String msg) {
+ super(internalMsgId, params, msg);
+ }
+
+ public InvalidProtocolRequestException(String internalMsgId, Object[] params, String msg, Throwable e) {
+ super(internalMsgId, params, msg, e);
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/NoPassivAuthenticationException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/NoPassivAuthenticationException.java
new file mode 100644
index 00000000..f4d40b6a
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/NoPassivAuthenticationException.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+import at.gv.egiz.eaaf.core.api.IStatusMessager;
+
+public class NoPassivAuthenticationException extends EAAFAuthenticationException {
+
+ public NoPassivAuthenticationException() {
+ super(IStatusMessager.CODES_INTERNAL_ERROR_AUTH_REQUEST_INVALID, null, "");
+ }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 596920452166197688L;
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/ProcessExecutionException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/ProcessExecutionException.java
new file mode 100644
index 00000000..db678e9b
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/ProcessExecutionException.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+/**
+ * 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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/ProtocolNotActiveException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/ProtocolNotActiveException.java
new file mode 100644
index 00000000..33597845
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/ProtocolNotActiveException.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+/**
+ * @author tlenz
+ *
+ */
+public class ProtocolNotActiveException extends EAAFProtocolException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1832697083163940710L;
+
+ public ProtocolNotActiveException(String internalMsgId, Object[] params, String msg) {
+ super(internalMsgId, params, msg);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/SLOException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/SLOException.java
new file mode 100644
index 00000000..66c18db6
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/SLOException.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+/**
+ * @author tlenz
+ *
+ */
+public class SLOException extends EAAFException {
+ private static final long serialVersionUID = -5284624715788385022L;
+
+ /**
+ * @param messageId
+ * @param parameters
+ */
+ public SLOException(String messageId, Object[] parameters) {
+ super(messageId, parameters, "SLO processing error");
+ // TODO Auto-generated constructor stub
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/TaskExecutionException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/TaskExecutionException.java
new file mode 100644
index 00000000..b6c6bd16
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/TaskExecutionException.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+import org.apache.commons.lang3.StringUtils;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+
+/**
+ * @author tlenz
+ *
+ */
+public class TaskExecutionException extends ProcessExecutionException {
+
+ private static final long serialVersionUID = 1L;
+ Throwable originalException = null;
+ String pendingRequestID = null;
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public TaskExecutionException(IRequest pendingReq, String message, Throwable cause) {
+ super(message, cause);
+ this.originalException = cause;
+
+ if (StringUtils.isNotEmpty(pendingReq.getPendingRequestId()))
+ this.pendingRequestID = pendingReq.getPendingRequestId();
+
+ }
+
+ /**
+ * Get the original internal exception from task
+ *
+ * @return the originalException
+ */
+ public Throwable getOriginalException() {
+ return originalException;
+
+ }
+
+ /**
+ * Get the pending-request ID of that request, which was processed when the exception occurs
+ *
+ * @return the pendingRequestID
+ */
+ public String getPendingRequestID() {
+ return pendingRequestID;
+ }
+
+
+
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/UnavailableAttributeException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/UnavailableAttributeException.java
new file mode 100644
index 00000000..f4d5bdae
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/UnavailableAttributeException.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.exceptions;
+
+public class UnavailableAttributeException extends AttributeBuilderException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -1114323185905118432L;
+
+ private String attributeName;
+
+ public UnavailableAttributeException(String attributeName) {
+ super("Attribute " + attributeName + " is not available.");
+ this.attributeName = attributeName;
+ }
+
+ public String getAttributeName() {
+ return attributeName;
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/XPathException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/XPathException.java
new file mode 100644
index 00000000..5cccbda4
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/exceptions/XPathException.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.exceptions;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * An exception occurred evaluating an XPath.
+ *
+ */
+public class XPathException extends RuntimeException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1736311265333034392L;
+/** The wrapped exception. */
+ private Throwable wrapped;
+
+ /**
+ * Create a <code>XPathException</code>.
+ *
+ * @param message The exception message.
+ * @param wrapped The exception being the likely cause of this exception.
+ */
+ public XPathException(String message, Throwable wrapped) {
+ super(message);
+ this.wrapped = wrapped;
+ }
+
+ public XPathException(String string) {
+ super(string);
+}
+
+/**
+ * Return the wrapped exception.
+ *
+ * @return The wrapped exception being the likely cause of this exception.
+ */
+ public Throwable getWrapped() {
+ return wrapped;
+ }
+
+ /**
+ * @see java.lang.Throwable#printStackTrace(java.io.PrintStream)
+ */
+ public void printStackTrace(PrintStream s) {
+ super.printStackTrace(s);
+ if (getWrapped() != null) {
+ s.print("Caused by: ");
+ getWrapped().printStackTrace(s);
+ }
+ }
+
+ /**
+ * @see java.lang.Throwable#printStackTrace(java.io.PrintWriter)
+ */
+ public void printStackTrace(PrintWriter s) {
+ super.printStackTrace(s);
+ if (getWrapped() != null) {
+ s.print("Caused by: ");
+ getWrapped().printStackTrace(s);
+ }
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/Pair.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/Pair.java
new file mode 100644
index 00000000..3277107f
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/Pair.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.data;
+
+public class Pair<P1, P2> {
+ private final P1 first;
+ private final P2 second;
+
+ private Pair(final P1 newFirst, final P2 newSecond) {
+ this.first = newFirst;
+ this.second = newSecond;
+ }
+
+ public P1 getFirst() {
+ return this.first;
+ }
+
+ public P2 getSecond() {
+ return this.second;
+ }
+
+ public static <P1, P2> Pair<P1, P2> newInstance(final P1 newFirst, final P2 newSecond) {
+ return new Pair<P1, P2>(newFirst, newSecond);
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/SLOInformationImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/SLOInformationImpl.java
new file mode 100644
index 00000000..46dce216
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/SLOInformationImpl.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.data;
+
+import java.io.Serializable;
+
+import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface;
+
+
+/**
+ * @author tlenz
+ *
+ */
+public class SLOInformationImpl implements SLOInformationInterface, Serializable {
+
+ private static final long serialVersionUID = 295577931870512387L;
+ private String sessionIndex = null;
+ private String nameID = null;
+ private String protocolType = null;
+ private String nameIDFormat = null;
+ private String binding = null;
+ private String serviceURL = null;
+ private String authURL = null;
+ private String spEntityID = null;
+
+ public SLOInformationImpl(String authURL, String spEntityID, String sessionID, String nameID, String nameIDFormat, String protocolType) {
+ new SLOInformationImpl(authURL, spEntityID, sessionID, nameID, nameIDFormat, protocolType, null, null);
+ }
+
+ public SLOInformationImpl(String authURL, String spEntityID, String sessionID, String nameID, String nameIDFormat, String protocolType, String sloBinding, String sloLocationURL) {
+ this.sessionIndex = sessionID;
+ this.nameID = nameID;
+ this.nameIDFormat = nameIDFormat;
+ this.protocolType = protocolType;
+ this.spEntityID = spEntityID;
+
+ if (authURL.endsWith("/"))
+ this.authURL = authURL.substring(0, authURL.length()-1);
+ else
+ this.authURL = authURL;
+
+
+ this.binding = sloBinding;
+ this.serviceURL = sloLocationURL;
+
+ }
+
+
+ /**
+ *
+ */
+ public SLOInformationImpl() {
+
+ }
+
+
+
+ /**
+ * @return the spEntityID
+ */
+ public String getSpEntityID() {
+ return spEntityID;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.data.SLOInformationInterface#getSessionIndex()
+ */
+ @Override
+ public String getSessionIndex() {
+ return sessionIndex;
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.data.SLOInformationInterface#getUserNameIdentifier()
+ */
+ @Override
+ public String getUserNameIdentifier() {
+ return nameID;
+
+ }
+
+
+ /**
+ * @param sessionIndex the sessionIndex to set
+ */
+ public void setSessionIndex(String sessionIndex) {
+ this.sessionIndex = sessionIndex;
+ }
+
+
+ /**
+ * @param nameID the nameID to set
+ */
+ public void setUserNameIdentifier(String nameID) {
+ this.nameID = nameID;
+ }
+
+
+
+ /**
+ * @param protocolType the protocolType to set
+ */
+ public void setProtocolType(String protocolType) {
+ this.protocolType = protocolType;
+ }
+
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.data.SLOInformationInterface#getProtocolType()
+ */
+ @Override
+ public String getProtocolType() {
+ return protocolType;
+ }
+
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.data.SLOInformationInterface#getUserNameIDFormat()
+ */
+ @Override
+ public String getUserNameIDFormat() {
+ return this.nameIDFormat;
+ }
+
+
+ /**
+ * @param nameIDFormat the nameIDFormat to set
+ */
+ public void setNameIDFormat(String nameIDFormat) {
+ this.nameIDFormat = nameIDFormat;
+ }
+
+ /**
+ * @return the binding
+ */
+ public String getBinding() {
+ return binding;
+ }
+
+ /**
+ * @return the serviceURL
+ */
+ public String getServiceURL() {
+ return serviceURL;
+ }
+
+ /**
+ * @return the authURL from requested IDP without ending /
+ */
+ public String getAuthURL() {
+ return authURL;
+ }
+
+ /**
+ * @param spEntityID the spEntityID to set
+ */
+ public void setSpEntityID(String spEntityID) {
+ this.spEntityID = spEntityID;
+ }
+
+
+
+
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/Trible.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/Trible.java
new file mode 100644
index 00000000..b817de42
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/data/Trible.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.data;
+
+public class Trible<P1, P2, P3> {
+ private final P1 first;
+ private final P2 second;
+ private final P3 third;
+
+ private Trible(final P1 newFirst, final P2 newSecond, final P3 newThird) {
+ this.first = newFirst;
+ this.second = newSecond;
+ this.third = newThird;
+ }
+
+ public P1 getFirst() {
+ return this.first;
+ }
+
+ public P2 getSecond() {
+ return this.second;
+ }
+
+ public P3 getThird() {
+ return this.third;
+ }
+
+ public static <P1, P2, P3> Trible<P1, P2, P3> newInstance(final P1 newFirst, final P2 newSecond, final P3 newThird) {
+ return new Trible<P1, P2, P3>(newFirst, newSecond, newThird);
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGUIFormBuilderConfiguration.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGUIFormBuilderConfiguration.java
new file mode 100644
index 00000000..0ab13a9b
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGUIFormBuilderConfiguration.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.gui;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
+import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfiguration;
+
+/**
+ * @author tlenz
+ *
+ */
+public abstract class AbstractGUIFormBuilderConfiguration implements IGUIBuilderConfiguration {
+
+ public static final String PARAM_AUTHCONTEXT = "contextPath";
+ public static final String PARAM_FORMSUBMITENDPOINT = "submitEndpoint";
+ public static final String PARAM_PENDINGREQUESTID = "pendingReqID";
+
+ private String authURL = null;
+ private String viewName = null;
+ private String formSubmitEndpoint = null;
+
+ /**
+ * @param authURL IDP PublicURL-Prefix which should be used, but never null
+ * @param viewName Name of the template (with suffix) but never null
+ * @param formSubmitEndpoint EndPoint on which the form should be submitted,
+ * or null if the form must not submitted
+ *
+ */
+ public AbstractGUIFormBuilderConfiguration(String authURL, String viewName, String formSubmitEndpoint) {
+ if (viewName.startsWith("/"))
+ this.viewName = viewName.substring(1);
+ else
+ this.viewName = viewName;
+
+ if (authURL.endsWith("/"))
+ this.authURL = authURL.substring(0, authURL.length() - 1);
+ else
+ this.authURL = authURL;
+
+ if (StringUtils.isNotEmpty(formSubmitEndpoint)) {
+ if (formSubmitEndpoint.startsWith("/"))
+ this.formSubmitEndpoint = formSubmitEndpoint;
+ else
+ this.formSubmitEndpoint = "/" + formSubmitEndpoint;
+ }
+ }
+
+
+ /**
+ * Define the parameters, which should be evaluated in the template <br>
+ * <b>IMPORTANT:</b> external HTML escapetion is required, because it is NOT done internally during the building process
+ *
+ * @return Map of parameters, which should be added to template
+ */
+ abstract protected Map<String, Object> getSpecificViewParameters();
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.frontend.builder.IGUIBuilderConfiguration#getViewName()
+ */
+ @Override
+ public final String getViewName() {
+ return this.viewName;
+
+ }
+
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.frontend.builder.IGUIBuilderConfiguration#getViewParameters()
+ */
+ @Override
+ public final Map<String, Object> getViewParameters() {
+ //get parameters from detail implementation
+ Map<String, Object> specParams = getSpecificViewParameters();
+ if (specParams == null)
+ specParams = new HashMap<String, Object>();
+
+ //add generic parameters
+ specParams.put(PARAM_AUTHCONTEXT, this.authURL);
+ if (this.formSubmitEndpoint != null)
+ specParams.put(PARAM_FORMSUBMITENDPOINT, this.formSubmitEndpoint);
+
+ return specParams;
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGUIFormBuilderImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGUIFormBuilderImpl.java
new file mode 100644
index 00000000..a71fc21e
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGUIFormBuilderImpl.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.gui;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfiguration;
+import at.gv.egiz.eaaf.core.api.gui.IGUIFormBuilder;
+import at.gv.egiz.eaaf.core.exceptions.GUIBuildException;
+import at.gv.egiz.eaaf.core.impl.gui.velocity.VelocityProvider;
+
+/**
+ * @author tlenz
+ *
+ */
+public abstract class AbstractGUIFormBuilderImpl implements IGUIFormBuilder {
+ private static final Logger log = LoggerFactory.getLogger(AbstractGUIFormBuilderImpl.class);
+ private static final String DEFAULT_CONTENT_TYPE = EAAFConstants.CONTENTTYPE_HTML_UTF8;
+
+ private VelocityEngine engine;
+
+ public AbstractGUIFormBuilderImpl() throws GUIBuildException {
+ try {
+ engine = VelocityProvider.getClassPathVelocityEngine();
+
+ } catch (Exception e) {
+ log.error("Initialization of Velocity-Engine to render GUI components FAILED.", e);
+ throw new GUIBuildException("Initialization of Velocity-Engine to render GUI components FAILED.", e);
+
+ }
+
+ }
+
+ public void build(HttpServletResponse httpResp, IGUIBuilderConfiguration config, String loggerName) throws GUIBuildException {
+ build(httpResp, config, getInternalContentType(config), loggerName);
+
+ }
+
+ @Override
+ public void build(HttpServletResponse httpResp, IGUIBuilderConfiguration config,
+ String contentType, String loggerName) throws GUIBuildException {
+
+ InputStream is = null;
+ try {
+ String viewName = config.getViewName();
+ is = getTemplateInputStream(config);
+
+ //build Velocity Context from input paramters
+ VelocityContext context = buildContextFromViewParams(config.getViewParameters());
+
+ //evaluate template
+ StringWriter writer = new StringWriter();
+ engine.evaluate(context, writer, loggerName, new BufferedReader(new InputStreamReader(is)));
+
+ //write template to response
+ final byte[] content = writer.toString().getBytes("UTF-8");
+ httpResp.setStatus(HttpServletResponse.SC_OK);
+ httpResp.setContentLength(content.length);
+ httpResp.setContentType(contentType);
+ httpResp.getOutputStream().write(content);
+
+ if (log.isTraceEnabled()) {
+ log.trace("Write Content for viewName:" + viewName
+ + ". Contentsize:" + String.valueOf(content.length)
+ + " BufferSize:" + httpResp.getBufferSize()
+ + " ContentType:" + contentType);
+ for (String el : httpResp.getHeaderNames())
+ log.trace(" * Headername:" + el + " Value:" + httpResp.getHeader(el));
+
+ }
+
+ } catch (IOException e) {
+ log.error("GUI form-builder has an internal error.", e);
+ throw new GUIBuildException("GUI form-builder has an internal error.", e);
+
+ } finally {
+ if (is != null)
+ try {
+ is.close();
+
+ } catch (IOException e) {
+ log.error("Can NOT close GUI-Template InputStream.", e);
+
+ }
+ }
+
+ }
+
+ /**
+ * Generate a new {@link VelocityContext} and populate it with MOA-ID GUI parameters
+ *
+ * @param config
+ * @return
+ */
+ public VelocityContext generateVelocityContextFromConfiguration(IGUIBuilderConfiguration config) {
+ return buildContextFromViewParams(config.getViewParameters());
+
+ }
+
+ /**
+ * Load the template from different resources
+ *
+ * @param config
+ * @return An {@link InputStream} but never null. The {@link InputStream} had to be closed be the invoking method
+ * @throws GUIBuildException
+ */
+ public InputStream getTemplateInputStream(IGUIBuilderConfiguration config) throws GUIBuildException {
+ InputStream is = config.getTemplate(config.getViewName());
+ if (is == null) {
+ log.trace("Loading GUI template:" + config.getViewName() + " from default resources ... ");
+ is = getInternalTemplate(config);
+
+ if (is == null) {
+ log.warn("No GUI with viewName:" + config.getViewName() + " FOUND.");
+ throw new GUIBuildException("No GUI with viewName:" + config.getViewName() + " FOUND.");
+
+ }
+ }
+ return is;
+
+ }
+
+ /**
+ * Load an internal template from default resources
+ *
+ * @param config
+ * @return
+ * @throws GUIBuildException
+ */
+ abstract protected InputStream getInternalTemplate(IGUIBuilderConfiguration config) throws GUIBuildException;
+
+
+ /**
+ * @return
+ */
+ protected String getInternalClasspathTemplateDir(IGUIBuilderConfiguration config, String defaultClassPathDir) {
+ String dir = config.getClasspathTemplateDir();
+ if (dir != null) {
+ if (!dir.endsWith("/"))
+ dir += "/";
+
+ return dir;
+
+ } else
+ return defaultClassPathDir;
+ }
+
+ /**
+ * @param viewParams
+ * @return
+ */
+ private VelocityContext buildContextFromViewParams(Map<String, Object> viewParams) {
+ VelocityContext context = new VelocityContext();
+
+ if (viewParams != null) {
+ Iterator<Entry<String, Object>> interator = viewParams.entrySet().iterator();
+ while (interator.hasNext()) {
+ Entry<String, Object> el = interator.next();
+ context.put(el.getKey(), el.getValue());
+ }
+
+ }
+
+ return context;
+ }
+
+ private String getInternalContentType(IGUIBuilderConfiguration config) {
+ if (StringUtils.isEmpty(config.getDefaultContentType()))
+ return DEFAULT_CONTENT_TYPE;
+
+ else
+ return config.getDefaultContentType();
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/velocity/VelocityLogAdapter.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/velocity/VelocityLogAdapter.java
new file mode 100644
index 00000000..51a59a8e
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/velocity/VelocityLogAdapter.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.gui.velocity;
+
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.log.LogChute;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VelocityLogAdapter implements LogChute {
+
+ private static final Logger log = LoggerFactory.getLogger(VelocityLogAdapter.class);
+
+ public VelocityLogAdapter() {
+ try
+ {
+ /*
+ * register this class as a logger with the Velocity singleton
+ * (NOTE: this would not work for the non-singleton method.)
+ */
+ Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, this );
+ Velocity.init();
+ }
+ catch (Exception e)
+ {
+ log.error("Failed to register Velocity logger");
+ }
+ }
+
+ public void init(RuntimeServices arg0) throws Exception {
+ }
+
+ public boolean isLevelEnabled(int arg0) {
+ switch(arg0) {
+ case LogChute.DEBUG_ID:
+ return log.isDebugEnabled();
+ case LogChute.TRACE_ID:
+ return log.isTraceEnabled();
+ default:
+ return true;
+ }
+ }
+
+ public void log(int arg0, String arg1) {
+ switch(arg0) {
+ case LogChute.DEBUG_ID:
+ log.debug(arg1);
+ break;
+ case LogChute.TRACE_ID:
+ log.trace(arg1);
+ break;
+ case LogChute.INFO_ID:
+ log.info(arg1);
+ break;
+ case LogChute.WARN_ID:
+ log.warn(arg1);
+ break;
+ case LogChute.ERROR_ID:
+ default:
+ log.error(arg1);
+ break;
+ }
+ }
+
+ public void log(int arg0, String arg1, Throwable arg2) {
+ switch(arg0) {
+ case LogChute.DEBUG_ID:
+ case LogChute.TRACE_ID:
+ case LogChute.INFO_ID:
+ case LogChute.WARN_ID:
+ log.warn(arg1, arg2);
+ break;
+ case LogChute.ERROR_ID:
+ default:
+ log.error(arg1, arg2);
+ break;
+ }
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/velocity/VelocityProvider.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/velocity/VelocityProvider.java
new file mode 100644
index 00000000..5775e203
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/velocity/VelocityProvider.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ ******************************************************************************/
+/*
+ * Copyright 2011 by Graz University of Technology, Austria
+ * The Austrian STORK Modules have been developed by the E-Government
+ * Innovation Center EGIZ, a joint initiative of the Federal Chancellery
+ * Austria and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
+
+/**
+ *
+ */
+package at.gv.egiz.eaaf.core.impl.gui.velocity;
+
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.RuntimeConstants;
+
+/**
+ * Gets a Velocity Engine
+ *
+ * @author bzwattendorfer
+ *
+ */
+public class VelocityProvider {
+
+ private static VelocityEngine velocityEngine = null;
+
+ /**
+ * Gets velocityEngine from Classpath
+ * @return VelocityEngine
+ * @throws Exception
+ */
+ public static VelocityEngine getClassPathVelocityEngine() throws Exception {
+ if (velocityEngine == null) {
+ velocityEngine = getBaseVelocityEngine();
+ velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
+ velocityEngine.setProperty("classpath.resource.loader.class",
+ "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+ velocityEngine.init();
+
+ }
+
+ return velocityEngine;
+ }
+
+ /**
+ * Gets VelocityEngine from File
+ * @param rootPath File Path to template file
+ * @return VelocityEngine
+ * @throws Exception
+ */
+ public static VelocityEngine getFileVelocityEngine(String rootPath) throws Exception {
+ if (velocityEngine == null) {
+ velocityEngine = getBaseVelocityEngine();
+ velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "file");
+ velocityEngine.setProperty("file.resource.loader.class",
+ "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+ velocityEngine.setProperty("file.resource.loader.path", rootPath);
+
+ velocityEngine.init();
+
+ }
+
+ return velocityEngine;
+ }
+
+ /**
+ * Gets a basic VelocityEngine
+ * @return VelocityEngine
+ */
+ private static VelocityEngine getBaseVelocityEngine() {
+ VelocityEngine velocityEngine = new VelocityEngine();
+ velocityEngine.setProperty(RuntimeConstants.INPUT_ENCODING, "UTF-8");
+ velocityEngine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
+// velocityEngine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+// "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
+ velocityEngine.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, new VelocityLogAdapter() );
+
+ return velocityEngine;
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/AuthenticationData.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/AuthenticationData.java
new file mode 100644
index 00000000..f35a54fa
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/AuthenticationData.java
@@ -0,0 +1,416 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp;
+
+import java.io.Serializable;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.apache.commons.collections4.map.HashedMap;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException;
+
+/**
+ * @author tlenz
+ *
+ */
+public class AuthenticationData implements IAuthData, Serializable {
+
+ private static final Logger log = LoggerFactory.getLogger(AuthenticationData.class);
+
+ private static final long serialVersionUID = -1042697056735596866L;
+ public static final String IDENTITY_LINK_DATE_FORMAT = "yyyy-MM-dd";
+
+ private boolean isBaseIDTransferRestrication = true;
+ private Map<String, Object> genericDataStorate = new HashedMap<String, Object>();
+
+ private String issuer;
+ private Date issueInstant;
+
+ private String identificationValue;
+ private String identificationType;
+ private IIdentityLink identityLink = null;
+
+ private String familyName;
+ private String givenName;
+ private Date dateOfBirth;
+ private String bPK;
+ private String bPKType;
+
+ private String ccc = null;
+
+
+ private boolean foreigner =false;
+ private String eIDASLoA = null;
+
+ private boolean ssoSession = false;
+ private Date ssoSessionValidTo = null;
+
+ private String sessionIndex = null;
+ private String nameID = null;
+ private String nameIDFormat = null;
+
+ public AuthenticationData() {
+ this.issueInstant = new Date();
+
+ }
+
+ @Override
+ public String getAuthenticationIssuer() {
+ return this.issuer;
+ }
+
+ /**
+ * Set an unique identifier for the IDP that authenticates the user
+ *
+ * @param authIssuer
+ */
+ public void setAuthenticationIssuer(String authIssuer) {
+ this.issuer = authIssuer;
+
+ }
+
+
+ @Override
+ public Date getAuthenticationIssueInstant() {
+ return this.issueInstant;
+ }
+
+
+ public String getAuthenticationIssueInstantString() {
+ SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ f.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return f.format(this.issueInstant);
+
+ }
+
+ /**
+ * Set the timestamp for this user authentication process
+ *
+ * @param date
+ */
+ public void setAuthenticationIssueInstant(Date date) {
+ this.issueInstant = date;
+ }
+
+ @Override
+ public String getCiticenCountryCode() {
+ return this.ccc;
+ }
+
+
+ public String getBPK() {
+ return bPK;
+ }
+
+ /**
+ * Sets the bPK.
+ * @param bPK The bPK to set
+ */
+ public void setBPK(String bPK) {
+ this.bPK = bPK;
+ }
+
+
+ public Date getDateOfBirth() {
+ return this.dateOfBirth;
+ }
+
+ public String getFormatedDateOfBirth() {
+ DateFormat pvpDateFormat = new SimpleDateFormat(IDENTITY_LINK_DATE_FORMAT);
+ if (getDateOfBirth() != null)
+ return pvpDateFormat.format(getDateOfBirth());
+ else
+ return "2999-12-31";
+
+ }
+
+
+ public String getFamilyName() {
+ return this.familyName;
+ }
+
+
+ public String getGivenName() {
+ return this.givenName;
+ }
+
+
+ public String getIdentificationValue() {
+ return identificationValue;
+ }
+
+
+ public String getIdentificationType() {
+ return identificationType;
+ }
+
+ @Override
+ public IIdentityLink getIdentityLink() {
+ return identityLink;
+ }
+
+ /**
+ * @param identityLink the identityLink to set
+ */
+ public void setIdentityLink(IIdentityLink identityLink) {
+ this.identityLink = identityLink;
+ }
+
+ /**
+ * Sets the dateOfBirth.
+ * @param dateOfBirth The dateOfBirth to set
+ */
+ public void setDateOfBirth(Date dateOfBirth) {
+ this.dateOfBirth = dateOfBirth;
+ }
+
+ public void setDateOfBirth(String dateOfBirth) {
+ try {
+ if (StringUtils.isNotEmpty(dateOfBirth)) {
+ DateFormat identityLinkFormat = new SimpleDateFormat(IDENTITY_LINK_DATE_FORMAT);
+ this.dateOfBirth = identityLinkFormat.parse(dateOfBirth);
+
+ }
+
+ } catch (ParseException e) {
+ log.warn("Parse dateOfBirht from IdentityLink FAILED", e);
+
+ }
+ }
+
+ /**
+ * Sets the familyName.
+ * @param familyName The familyName to set
+ */
+ public void setFamilyName(String familyName) {
+ this.familyName = familyName;
+ }
+
+ /**
+ * Sets the givenName.
+ * @param givenName The givenName to set
+ */
+ public void setGivenName(String givenName) {
+ this.givenName = givenName;
+ }
+
+ /**
+ * Sets the identificationValue.
+ * @param identificationValue The identificationValue to set
+ */
+ public void setIdentificationValue(String identificationValue) {
+ this.identificationValue = identificationValue;
+ }
+
+ /**
+ * Sets the identificationType.
+ * @param identificationType The identificationType to set
+ */
+ public void setIdentificationType(String identificationType) {
+ this.identificationType = identificationType;
+ }
+
+
+ public String getBPKType() {
+ return bPKType;
+ }
+
+ /**
+ * Set sector identifier of user's bPK
+ *
+ * @param bPKType
+ */
+ public void setBPKType(String bPKType) {
+ this.bPKType = bPKType;
+ }
+
+ public String getEIDASQAALevel() {
+ return this.eIDASLoA;
+
+ }
+
+
+ public boolean isForeigner() {
+ return this.foreigner;
+ }
+
+
+ /**
+ * Indicate the the user is a foreigner
+ *
+ * @param true if the user is a foreigner, otherwise false
+ */
+ public void setForeigner(boolean foreigner) {
+ this.foreigner = foreigner;
+ }
+
+ @Override
+ public boolean isSsoSession() {
+ return ssoSession;
+ }
+
+
+ /**
+ * Indicate that the authentication was done by using an active SSO session
+ *
+ * @param true if a SSO was used, otherwise false
+ */
+ public void setSsoSession(boolean ssoSession) {
+ this.ssoSession = ssoSession;
+ }
+
+
+ /**
+ * Country Code for the authenticated user
+ *
+ * @param ccc Two letter country code
+ */
+ public void setCiticenCountryCode(String ccc) {
+ this.ccc = ccc;
+ }
+
+ public String getSessionIndex() {
+ return sessionIndex;
+ }
+
+ /**
+ * @param sessionIndex the sessionIndex to set
+ */
+ public void setSessionIndex(String sessionIndex) {
+ this.sessionIndex = sessionIndex;
+ }
+
+
+ @Override
+ public String getNameID() {
+ return this.nameID;
+ }
+
+ /**
+ * @param nameID the nameID to set
+ */
+ public void setNameID(String nameID) {
+ this.nameID = nameID;
+ }
+
+ /**
+ * @return the nameIDFormat
+ */
+ public String getNameIDFormat() {
+ return nameIDFormat;
+ }
+
+ /**
+ * @param nameIDFormat the nameIDFormat to set
+ */
+ public void setNameIDFormat(String nameIDFormat) {
+ this.nameIDFormat = nameIDFormat;
+ }
+
+ /**
+ * @return the ssoSessionValidTo
+ */
+ public Date getSsoSessionValidTo() {
+ return ssoSessionValidTo;
+ }
+
+ /**
+ * @param ssoSessionValidTo the ssoSessionValidTo to set
+ */
+ public void setSsoSessionValidTo(Date ssoSessionValidTo) {
+ this.ssoSessionValidTo = ssoSessionValidTo;
+ }
+
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.data.IAuthData#isBusinessService()
+ */
+ @Override
+ public boolean isBaseIDTransferRestrication() {
+ return isBaseIDTransferRestrication;
+ }
+
+ /**
+ * @param isBaseIDTransmittionAllowed the isBaseIDTransmittionAllowed to set
+ */
+ public void setBaseIDTransferRestrication(boolean isBaseIDTransferRestrication) {
+ this.isBaseIDTransferRestrication = isBaseIDTransferRestrication;
+ }
+
+ /**
+ * Returns a generic data-object with is stored with a specific identifier
+ *
+ * @param key The specific identifier of the data object
+ * @param clazz The class type which is stored with this key
+ * @return The data object or null if no data is found with this key
+ */
+ public <T> T getGenericData(String key, final Class<T> clazz) {
+ if (StringUtils.isNotEmpty(key)) {
+ Object data = genericDataStorate.get(key);
+
+ if (data == null)
+ return null;
+
+ try {
+ @SuppressWarnings("unchecked")
+ T test = (T) data;
+ return test;
+
+ } catch (Exception e) {
+ log.warn("Generic authentication-data object can not be casted to requsted type", e);
+ return null;
+
+ }
+
+ }
+
+ log.info("Can not load generic session-data with key='null'");
+ return null;
+
+ }
+
+ /**
+ * Store a generic data-object to session with a specific identifier
+ *
+ * @param key Identifier for this data-object
+ * @param object Generic data-object which should be stored. This data-object had to be implement the 'java.io.Serializable' interface
+ * @throws SessionDataStorageException Error message if the data-object can not stored to generic session-data storage
+ */
+ public void setGenericData(String key, Object object) throws EAAFStorageException {
+ if (StringUtils.isEmpty(key)) {
+ log.info("Generic session-data can not be stored with a 'null' key");
+ throw new EAAFStorageException("Generic data can not be stored with a 'null' key", null);
+
+ }
+
+ if (object != null) {
+ if (!Serializable.class.isInstance(object)) {
+ log.warn("Generic data can only store objects which implements the 'Seralizable' interface");
+ throw new EAAFStorageException("Generic data can only store objects which implements the 'Seralizable' interface", null);
+
+ }
+ }
+
+ if (genericDataStorate.containsKey(key))
+ log.debug("Overwrite generic data with key:" + key);
+ else
+ log.trace("Add generic data with key:" + key + " to session.");
+
+ genericDataStorate.put(key, object);
+ }
+
+ public void seteIDASLoA(String eIDASLoA) {
+ this.eIDASLoA = eIDASLoA;
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/EAAFCoreSpringResourceProvider.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/EAAFCoreSpringResourceProvider.java
new file mode 100644
index 00000000..a289f49d
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/EAAFCoreSpringResourceProvider.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+import at.gv.egiz.components.spring.api.SpringResourceProvider;
+
+public class EAAFCoreSpringResourceProvider implements SpringResourceProvider {
+
+ @Override
+ public String getName() {
+ return "EAAF Core SpringResourceProvider";
+ }
+
+ @Override
+ public String[] getPackagesToScan() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Resource[] getResourcesToLoad() {
+ ClassPathResource sl20AuthConfig = new ClassPathResource("/eaaf_core.beans.xml", EAAFCoreSpringResourceProvider.class);
+
+ return new Resource[] {sl20AuthConfig};
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/AbstractAuthenticationManager.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/AbstractAuthenticationManager.java
new file mode 100644
index 00000000..e52a7884
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/AbstractAuthenticationManager.java
@@ -0,0 +1,341 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.auth;
+
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.text.StringEscapeUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.IRequestStorage;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.auth.IAuthenticationManager;
+import at.gv.egiz.eaaf.core.api.idp.auth.ISSOManager;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine;
+import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFSSOException;
+import at.gv.egiz.eaaf.core.exceptions.NoPassivAuthenticationException;
+import at.gv.egiz.eaaf.core.exceptions.ProcessExecutionException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.ModuleRegistration;
+import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl;
+import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl;
+import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils;
+
+public abstract class AbstractAuthenticationManager implements IAuthenticationManager {
+ private static final Logger log = LoggerFactory.getLogger(AbstractAuthenticationManager.class);
+
+ private static List<String> reqParameterWhiteListeForModules = new ArrayList<String>();
+ private static List<String> reqHeaderWhiteListeForModules = new ArrayList<String>();
+
+ public static final String MOA_SESSION = "MoaAuthenticationSession";
+ public static final String MOA_AUTHENTICATED = "MoaAuthenticated";
+
+ public static final int SLOTIMEOUT = 30 * 1000; //30 sec
+
+ @Autowired(required=true) protected IConfiguration authConfig;
+ @Autowired(required=true) private ProcessEngine processEngine;
+ @Autowired(required=true) private IRequestStorage requestStoreage;
+ @Autowired(required=true) protected IRevisionLogger revisionsLogger;
+ @Autowired(required=false) protected ISSOManager ssoManager;
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.eaaf.core.impl.idp.auth.IAuthenticationManager#addParameterNameToWhiteList(java.lang.String)
+ */
+ @Override
+ public final void addParameterNameToWhiteList(String httpReqParam) {
+ if (StringUtils.isNotEmpty(httpReqParam))
+ reqParameterWhiteListeForModules.add(httpReqParam);
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.eaaf.core.impl.idp.auth.IAuthenticationManager#addHeaderNameToWhiteList(java.lang.String)
+ */
+ @Override
+ public final void addHeaderNameToWhiteList(String httpReqParam) {
+ if (StringUtils.isNotEmpty(httpReqParam))
+ reqHeaderWhiteListeForModules.add(httpReqParam.toLowerCase());
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egiz.eaaf.core.impl.idp.auth.IAuthenticationManager#addHeaderNameToWhiteList(java.lang.String)
+ */
+ @Override
+ public final boolean doAuthentication(HttpServletRequest httpReq, HttpServletResponse httpResp,
+ IRequest pendingReq) throws EAAFException {
+
+ if (!(pendingReq instanceof RequestImpl)) {
+ log.error("Requests that need authentication MUST be of type 'RequestImpl'");
+ throw new RuntimeException("Requests that need authentication HAS TO BE of type 'RequestImpl'");
+
+ }
+
+ //load OA configuration from pending request
+ ISPConfiguration oaParam = pendingReq.getServiceProviderConfiguration();
+
+ //set logging context and log unique OA identifier to revision log
+ TransactionIDUtils.setServiceProviderId(oaParam.getUniqueIdentifier());
+ revisionsLogger.logEvent(pendingReq, EVENT_AUTHENTICATION_PROCESS_FOR_SP, pendingReq.getSPEntityId());
+
+ //generic authentication request validation
+ if (pendingReq.isPassiv() && pendingReq.forceAuth()) {
+ // conflict!
+ throw new NoPassivAuthenticationException();
+ }
+
+
+ //check Single Sign-On functionality if SSOManager is available
+ boolean isValidSSOSession = false;
+ if (ssoManager != null) {
+ log.trace("SSOManager is loaded. Starting SSO session validation ... ");
+ //check if SSO is allowed for this service provider
+ ssoManager.isSSOAllowedForSP(pendingReq, httpReq);
+
+ //check if SSO session is active and valid
+ isValidSSOSession = ssoManager.checkAndValidateSSOSession(pendingReq, httpReq, httpResp);
+
+ }
+
+ //check if session is already authenticated
+ //boolean isSessionAuthenticated = tryPerformAuthentication((RequestImpl) pendingReq, isValidSSOSession);
+ //boolean isSessionAuthenticated = isValidSSOSession && StringUtils.isNotEmpty(pendingReq.getSSOSessionIdentifier());
+
+
+ //force new authentication authentication process
+ if (pendingReq.forceAuth()) {
+ startAuthenticationProcess(httpReq, httpResp, (RequestImpl) pendingReq);
+ return false;
+
+ //perform SSO-Consents evaluation if it it required
+ } else if (isValidSSOSession && pendingReq.isNeedUserConsent()) {
+ sendSingleSignOnConsentsEvaluation(httpReq, httpResp, (RequestImpl) pendingReq);
+ return false;
+
+
+ } else if (pendingReq.isPassiv()) {
+ if (isValidSSOSession &&
+ StringUtils.isNotEmpty(pendingReq.getSSOSessionIdentifier()) ) {
+ // Passive authentication ok! --> Populate pending request from SSO session
+ ssoManager.populatePendingRequestWithSSOInformation(pendingReq);
+ revisionsLogger.logEvent(pendingReq, EVENT_AUTHENTICATION_PROCESS_FINISHED);
+ return true;
+
+ } else {
+ throw new NoPassivAuthenticationException();
+
+ }
+
+ } else {
+ if (isValidSSOSession &&
+ StringUtils.isNotEmpty(pendingReq.getSSOSessionIdentifier())) {
+ // Is authenticated .. proceed
+ ssoManager.populatePendingRequestWithSSOInformation(pendingReq);
+ revisionsLogger.logEvent(pendingReq, EVENT_AUTHENTICATION_PROCESS_FINISHED);
+ return true;
+
+ } else {
+ // Start authentication!
+ startAuthenticationProcess(httpReq, httpResp, (RequestImpl) pendingReq);
+ return false;
+
+ }
+ }
+ }
+
+ public final void performOnlyIDPLogOut(HttpServletRequest request, HttpServletResponse response, IRequest pendingReq) {
+
+ log.debug("Close session. Remove pending request ... ");
+ requestStoreage.removePendingRequest(pendingReq.getPendingRequestId());
+
+
+ if (ssoManager != null) {
+ try {
+ log.trace("'SSOManager' active. Search for active SSO sessions ... ");
+ if (ssoManager.destroySSOSessionOnIDPOnly(request, response, pendingReq))
+ log.info("SSO session successfully closed");
+ else
+ log.info("Closing SSO session NOT successfully");
+
+ } catch (EAAFSSOException e) {
+ log.warn("Destroying of SSO session FAILED. Reason: " + e.getMessage(), e);
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Populate process execution context and start process engine
+ *
+ * @param httpReq
+ * @param httpResp
+ * @param pendingReq
+ * @throws ServletException
+ * @throws IOException
+ * @throws EAAFException
+ */
+ private void startAuthenticationProcess(HttpServletRequest httpReq,
+ HttpServletResponse httpResp, RequestImpl pendingReq)
+ throws EAAFException {
+
+ log.info("Starting authentication ...");
+ revisionsLogger.logEvent(pendingReq, EVENT_AUTHENTICATION_PROCESS_STARTED);
+
+ //create authentication process execution context
+ ExecutionContext executionContext = new ExecutionContextImpl();
+
+ //set oaIdentifeir
+ executionContext.put(EAAFConstants.PROCESS_ENGINE_SERVICE_PROVIDER_ENTITYID,
+ pendingReq.getServiceProviderConfiguration().getUniqueIdentifier());
+
+ //add X509 SSL client certificate if exist
+ if (httpReq.getAttribute("javax.servlet.request.X509Certificate") != null) {
+ log.debug("Find SSL-client-certificate on request --> Add it to context");
+ executionContext.put(EAAFConstants.PROCESS_ENGINE_SSL_CLIENT_CERTIFICATE,
+ ((X509Certificate[])httpReq.getAttribute("javax.servlet.request.X509Certificate")));
+ pendingReq.setGenericDataToSession(EAAFConstants.PROCESS_ENGINE_SSL_CLIENT_CERTIFICATE,
+ ((X509Certificate[])httpReq.getAttribute("javax.servlet.request.X509Certificate")));
+
+ }
+
+ //add additional http request parameter to context
+ if (!reqParameterWhiteListeForModules.isEmpty()) {
+ Enumeration<String> reqParamNames = httpReq.getParameterNames();
+ while(reqParamNames.hasMoreElements()) {
+ String paramName = reqParamNames.nextElement();
+ if (StringUtils.isNotEmpty(paramName) && reqParameterWhiteListeForModules.contains(paramName) )
+ executionContext.put(paramName, StringEscapeUtils.escapeHtml4(httpReq.getParameter(paramName)));
+ }
+ }
+
+ //add additional http request parameter to context
+ if (!reqHeaderWhiteListeForModules.isEmpty()) {
+ Enumeration<String> reqHeaderNames = httpReq.getHeaderNames();
+ while(reqHeaderNames.hasMoreElements()) {
+ String paramName = reqHeaderNames.nextElement();
+ if (StringUtils.isNotEmpty(paramName) && reqHeaderWhiteListeForModules.contains(paramName.toLowerCase()) )
+ executionContext.put(paramName, StringEscapeUtils.escapeHtml4(httpReq.getHeader(paramName)));
+
+ }
+ }
+
+ //populate more IDP specific information to execution context
+ populateExecutionContext(executionContext, pendingReq, httpReq);
+
+ //start process engine
+ startProcessEngine(pendingReq, executionContext);
+
+ }
+
+ /**
+ *
+ *
+ * @throws EAAFException
+ */
+ abstract protected void populateExecutionContext(ExecutionContext executionContext,
+ RequestImpl pendingReq, HttpServletRequest httpReq) throws EAAFException;
+
+ /**
+ * Starting a user consent evaluation
+ *
+ * @param request
+ * @param response
+ * @param pendingReq
+ * @throws ServletException
+ * @throws IOException
+ * @throws EAAFException
+ */
+ private void sendSingleSignOnConsentsEvaluation(HttpServletRequest request,
+ HttpServletResponse response, RequestImpl pendingReq)
+ throws EAAFException {
+
+ log.debug("Starting SSO user-consents evaluation ...");
+
+ //set authenticated flag to false, because user consents is required
+ pendingReq.setAuthenticated(false);
+
+ //create execution context
+ ExecutionContext executionContext = new ExecutionContextImpl();
+ executionContext.put(ISSOManager.PROCESS_ENGINE_SSO_CONSENTS_EVALUATION, true);
+
+ //start process engine
+ startProcessEngine(pendingReq, executionContext);
+
+ }
+
+
+ /**
+ * Select a specific process and starting process engine
+ *
+ * @param pendingReq
+ * @param executionContext
+ * @throws EAAFException
+ */
+ private void startProcessEngine(RequestImpl pendingReq, ExecutionContext executionContext) throws EAAFException {
+ try {
+ //put pending-request ID on execurtionContext
+ executionContext.put(EAAFConstants.PROCESS_ENGINE_PENDINGREQUESTID, pendingReq.getPendingRequestId());
+
+ // create process instance
+ String processDefinitionId = ModuleRegistration.getInstance().selectProcess(executionContext);
+
+ if (processDefinitionId == null) {
+ log.warn("No suitable process found for PendingReqId " + pendingReq.getPendingRequestId() );
+ throw new EAAFException(
+ "process.02",
+ new Object[] {pendingReq.getPendingRequestId()}
+ ,"No suitable process found for PendingReqId " + pendingReq.getPendingRequestId());
+
+ }
+
+ String processInstanceId = processEngine.createProcessInstance(processDefinitionId, executionContext);
+
+ // keep process instance id in protocol pending-request
+ pendingReq.setProcessInstanceId(processInstanceId);
+
+ //store pending-request
+ requestStoreage.storePendingRequest(pendingReq);
+
+ // start process
+ processEngine.start(pendingReq);
+
+ } catch (ProcessExecutionException e) {
+ Throwable cause = e.getCause();
+ if (cause != null && cause instanceof TaskExecutionException) {
+ Throwable taskCause = cause.getCause();
+ if (taskCause != null && taskCause instanceof EAAFException) {
+ EAAFException moaTaskCause = (EAAFException) taskCause;
+ log.warn(taskCause.getMessage(), taskCause);
+ throw moaTaskCause;
+
+ }
+ }
+
+ throw new EAAFException(
+ "process.01",
+ new Object[] { pendingReq.getProcessInstanceId(), pendingReq.getPendingRequestId() },
+ "Authentication process execution FAILED",
+ e);
+ }
+
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java
new file mode 100644
index 00000000..7e0d4cc7
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.auth;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.IRequestStorage;
+import at.gv.egiz.eaaf.core.api.idp.process.ProcessInstanceStoreDAO;
+import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException;
+import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl;
+import at.gv.egiz.eaaf.core.impl.utils.Random;
+import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils;
+
+@Service("RequestStorage")
+public class RequestStorage implements IRequestStorage{
+ private static final Logger log = LoggerFactory.getLogger(RequestStorage.class);
+
+ @Autowired ITransactionStorage transactionStorage;
+ @Autowired ProcessInstanceStoreDAO processInstanceStore;
+
+ @Override
+ public IRequest getPendingRequest(String pendingReqID) {
+
+ try {
+ IRequest pendingRequest = transactionStorage.get(pendingReqID, IRequest.class);
+ if (pendingRequest == null) {
+ log.info("No PendingRequst found with pendingRequestID " + pendingReqID);
+ return null;
+
+ }
+
+ //set transactionID and sessionID to Logger
+ TransactionIDUtils.setAllLoggingVariables(pendingRequest);
+
+ return pendingRequest;
+
+ } catch (EAAFException | NullPointerException e) {
+ log.info("No PendingRequst found with pendingRequestID " + pendingReqID);
+ return null;
+
+ }
+ }
+
+ @Override
+ public void storePendingRequest(IRequest pendingRequest) throws EAAFException {
+ try {
+ if (pendingRequest instanceof IRequest)
+ transactionStorage.put(((IRequest)pendingRequest).getPendingRequestId(), pendingRequest, -1);
+
+ else
+ throw new EAAFException("PendigRequest is NOT of type 'IRequest'", null);
+
+
+ } catch (EAAFException e) {
+ log.warn("PendingRequest with ID=" + ((IRequest)pendingRequest).getPendingRequestId() +
+ " can not stored.", e);
+ throw new EAAFStorageException("PendingRequest with Id: " + ((IRequest)pendingRequest).getPendingRequestId()
+ + " can not be stored", e);
+
+ }
+
+ }
+
+ @Override
+ public void removePendingRequest(String requestID) {
+
+ if (requestID != null) {
+
+ //remove process-management execution instance
+ try {
+ IRequest pendingReq = getPendingRequest(requestID);
+
+ if (pendingReq != null &&
+ pendingReq.getProcessInstanceId() != null)
+ processInstanceStore.remove(pendingReq.getProcessInstanceId());
+
+ } catch (EAAFException e) {
+ log.warn("Removing process associated with pending-request:" + requestID + " FAILED.", e);
+
+ }
+
+ transactionStorage.remove(requestID);
+
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.storage.IRequestStorage#changePendingRequestID(at.gv.egovernment.moa.id.moduls.IRequest)
+ */
+ @Override
+ public String changePendingRequestID(IRequest pendingRequest) throws EAAFException {
+
+ if (pendingRequest instanceof RequestImpl) {
+ String newRequestID = Random.nextHexRandom32();
+ String oldRequestID = pendingRequest.getPendingRequestId();
+
+ log.debug("Change pendingRequestID from " + pendingRequest.getPendingRequestId()
+ + " to " + newRequestID);
+
+ ((RequestImpl)pendingRequest).setPendingRequestId(newRequestID);
+ transactionStorage.changeKey(oldRequestID, newRequestID, pendingRequest);
+
+ //only delete oldRequestID, no change.
+
+ return newRequestID;
+
+ } else {
+ log.error("PendingRequest object is not of type 'RequestImpl.class'");
+ throw new EAAFException("PendingRequest object is not of type 'RequestImpl.class'", null);
+ }
+
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/AbstractAuthenticationDataBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/AbstractAuthenticationDataBuilder.java
new file mode 100644
index 00000000..561f6f32
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/AbstractAuthenticationDataBuilder.java
@@ -0,0 +1,467 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.auth.builder;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.Base64Utils;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.data.PVPAttributeDefinitions;
+import at.gv.egiz.eaaf.core.api.idp.IAuthenticationDataBuilder;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IAuthProcessDataContainer;
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+import at.gv.egiz.eaaf.core.exceptions.EAAFBuilderException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFParserException;
+import at.gv.egiz.eaaf.core.exceptions.XPathException;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.idp.AuthenticationData;
+import at.gv.egiz.eaaf.core.impl.idp.auth.data.SimpleIdentityLinkAssertionParser;
+import at.gv.egiz.eaaf.core.impl.utils.XPathUtils;
+
+
+public abstract class AbstractAuthenticationDataBuilder implements IAuthenticationDataBuilder {
+ private static final Logger log = LoggerFactory.getLogger(AbstractAuthenticationDataBuilder.class);
+ protected Collection<String> includedToGenericAuthData = null;
+ @Autowired protected IConfiguration basicConfig;
+
+ protected void generateBasicAuthData(AuthenticationData authData, IRequest pendingReq,
+ IAuthProcessDataContainer authProcessData) throws EAAFBuilderException, EAAFConfigurationException, XPathException, DOMException, EAAFParserException {
+
+ if (authProcessData.getGenericSessionDataStorage() != null &&
+ !authProcessData.getGenericSessionDataStorage().isEmpty())
+ includedToGenericAuthData = authProcessData.getGenericSessionDataStorage().keySet();
+ else
+ includedToGenericAuthData = new ArrayList<String>();
+
+ //####################################################
+ //set general authData info's
+ authData.setAuthenticationIssuer(pendingReq.getAuthURL());
+ authData.setSsoSession(pendingReq.needSingleSignOnFunctionality());
+ authData.setBaseIDTransferRestrication(pendingReq.getServiceProviderConfiguration().hasBaseIdTransferRestriction());
+
+
+ //####################################################
+ //parse user info's from identityLink
+ IIdentityLink idlFromPVPAttr = null;
+ IIdentityLink identityLink = authProcessData.getIdentityLink();
+ if (identityLink != null) {
+ parseBasicUserInfosFromIDL(authData, identityLink, includedToGenericAuthData);
+
+ } else {
+ // identityLink is not direct in MOASession
+ String pvpAttrIDL = authProcessData.getGenericDataFromSession(PVPAttributeDefinitions.EID_IDENTITY_LINK_NAME, String.class);
+ //find PVP-Attr. which contains the IdentityLink
+ if (StringUtils.isNotEmpty(pvpAttrIDL)) {
+ log.debug("Find PVP-Attr: " + PVPAttributeDefinitions.EID_IDENTITY_LINK_FRIENDLY_NAME
+ + " --> Parse basic user info's from that attribute.");
+ InputStream idlStream = null;
+ try {
+ idlStream = new ByteArrayInputStream(Base64Utils.decodeFromString(pvpAttrIDL));
+ idlFromPVPAttr = new SimpleIdentityLinkAssertionParser(idlStream).parseIdentityLink();
+ parseBasicUserInfosFromIDL(authData, idlFromPVPAttr, includedToGenericAuthData);
+
+ //set identitylink into AuthProcessData
+ authProcessData.setIdentityLink(idlFromPVPAttr);;
+
+ } catch (EAAFParserException e) {
+ log.warn("Received IdentityLink is not valid", e);
+
+ } catch (Exception e) {
+ log.warn("Received IdentityLink is not valid", e);
+
+ } finally {
+ try {
+ includedToGenericAuthData.remove(PVPAttributeDefinitions.EID_IDENTITY_LINK_NAME);
+ if (idlStream != null)
+ idlStream.close();
+
+ } catch (IOException e) {
+ log.warn("Close InputStream FAILED.", e);
+
+ }
+ }
+ }
+
+ //if no basic user info's are set yet, parse info's single PVP-Attributes
+ if (StringUtils.isEmpty(authData.getFamilyName())) {
+ log.debug("No IdentityLink found or not parseable --> Parse basic user info's from single PVP-Attributes.");
+ authData.setFamilyName(authProcessData.getGenericDataFromSession(PVPAttributeDefinitions.PRINCIPAL_NAME_NAME, String.class));
+ authData.setGivenName(authProcessData.getGenericDataFromSession(PVPAttributeDefinitions.GIVEN_NAME_NAME, String.class));
+ authData.setDateOfBirth(authProcessData.getGenericDataFromSession(PVPAttributeDefinitions.BIRTHDATE_NAME, String.class));
+ authData.setIdentificationValue(authProcessData.getGenericDataFromSession(PVPAttributeDefinitions.EID_SOURCE_PIN_NAME, String.class));
+ authData.setIdentificationType(authProcessData.getGenericDataFromSession(PVPAttributeDefinitions.EID_SOURCE_PIN_TYPE_NAME, String.class));
+
+ //remove corresponding keys from genericSessionData if exists
+ includedToGenericAuthData.remove(PVPAttributeDefinitions.PRINCIPAL_NAME_NAME);
+ includedToGenericAuthData.remove(PVPAttributeDefinitions.GIVEN_NAME_NAME);
+ includedToGenericAuthData.remove(PVPAttributeDefinitions.BIRTHDATE_NAME);
+ includedToGenericAuthData.remove(PVPAttributeDefinitions.EID_SOURCE_PIN_NAME);
+ includedToGenericAuthData.remove(PVPAttributeDefinitions.EID_SOURCE_PIN_TYPE_NAME);
+ }
+
+ }
+
+ if (authData.getIdentificationType() != null &&
+ !authData.getIdentificationType().equals(EAAFConstants.URN_PREFIX_BASEID)) {
+ log.trace("IdentificationType is not a baseID --> clear it. ");
+ authData.setBPK(authData.getIdentificationValue());
+ authData.setBPKType(authData.getIdentificationType());
+
+ authData.setIdentificationValue(null);
+ authData.setIdentificationType(null);
+ }
+
+ //####################################################
+ //set QAA level
+ includedToGenericAuthData.remove(PVPAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME);
+ String currentLoA = null;
+ if (StringUtils.isNotEmpty(authProcessData.getQAALevel()))
+ currentLoA = authProcessData.getQAALevel();
+ else {
+ currentLoA = authProcessData.getGenericDataFromSession(PVPAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, String.class);
+ if (StringUtils.isNotEmpty(currentLoA)) {
+ log.debug("Find PVP-Attr '" + PVPAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_FRIENDLY_NAME + "':" + currentLoA
+ + " --> Parse QAA-Level from that attribute.");
+
+ }
+ }
+ if (StringUtils.isNotEmpty(currentLoA)) {
+ if (currentLoA.startsWith(EAAFConstants.EIDAS_QAA_PREFIX)) {
+ authData.seteIDASLoA(currentLoA);
+
+ } else
+ log.info("Only eIDAS LoAs are supported by this implementation");
+
+ } else {
+ log.info("No QAA level found. Set to default level " + EAAFConstants.EIDAS_QAA_LOW);
+ authData.seteIDASLoA(EAAFConstants.EIDAS_QAA_LOW);
+
+ }
+
+ //####################################################
+ //set isForeigner flag
+ //TODO: change to new eIDAS-token attribute identifier
+ if (authProcessData.getGenericDataFromSession(PVPAttributeDefinitions.EID_STORK_TOKEN_NAME) != null) {
+ log.debug("Find PVP-Attr: " + PVPAttributeDefinitions.EID_STORK_TOKEN_FRIENDLY_NAME
+ + " --> Set 'isForeigner' flag to TRUE");
+ authData.setForeigner(true);
+
+ } else {
+ authData.setForeigner(authProcessData.isForeigner());
+
+ }
+
+ //####################################################
+ //set citizen country-code
+ includedToGenericAuthData.remove(PVPAttributeDefinitions.EID_ISSUING_NATION_NAME);
+ String pvpCCCAttr = authProcessData.getGenericDataFromSession(PVPAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class);
+ if (StringUtils.isNotEmpty(pvpCCCAttr)) {
+ authData.setCiticenCountryCode(pvpCCCAttr);
+ log.debug("Find PVP-Attr: " + PVPAttributeDefinitions.EID_ISSUING_NATION_FRIENDLY_NAME);
+
+ } else {
+ if (authData.isForeigner()) {
+ //TODO!!!!
+
+ } else {
+ authData.setCiticenCountryCode(basicConfig.getBasicConfiguration(
+ IConfiguration.CONFIG_PROPS_AUTH_DEFAULT_COUNTRYCODE,
+ EAAFConstants.COUNTRYCODE_AUSTRIA));
+
+ }
+ }
+
+
+ //####################################################
+ // set bPK and IdentityLink
+ String pvpbPKValue = getbPKValueFromPVPAttribute(authProcessData);
+ String pvpbPKTypeAttr = getbPKTypeFromPVPAttribute(authProcessData);
+ Pair<String, String> pvpEncbPKAttr = getEncryptedbPKFromPVPAttribute(authProcessData, authData, pendingReq.getServiceProviderConfiguration());
+
+ //check if a unique ID for this citizen exists
+ if (StringUtils.isEmpty(authData.getIdentificationValue()) &&
+ StringUtils.isEmpty(pvpbPKValue) && StringUtils.isEmpty(authData.getBPK()) &&
+ pvpEncbPKAttr == null) {
+ log.info("Can not build authData, because moaSession include no bPK, encrypted bPK or baseID");
+ throw new EAAFBuilderException("builder.08", new Object[]{"No " + PVPAttributeDefinitions.BPK_FRIENDLY_NAME
+ + " or " + PVPAttributeDefinitions.EID_SOURCE_PIN_FRIENDLY_NAME
+ + " or " + PVPAttributeDefinitions.ENC_BPK_LIST_FRIENDLY_NAME},
+ "No " + PVPAttributeDefinitions.BPK_FRIENDLY_NAME
+ + " or " + PVPAttributeDefinitions.EID_SOURCE_PIN_FRIENDLY_NAME
+ + " or " + PVPAttributeDefinitions.ENC_BPK_LIST_FRIENDLY_NAME);
+
+ }
+
+ // baseID is in MOASesson --> calculate bPK directly
+ if (StringUtils.isNotEmpty(authData.getIdentificationValue())) {
+ log.debug("Citizen baseID is in MOASession --> calculate bPK from this.");
+ Pair<String, String> result = buildOAspecificbPK(pendingReq, authData);
+ authData.setBPK(result.getFirst());
+ authData.setBPKType(result.getSecond());
+
+ //check if bPK already added to AuthData matches OA
+ } else if (StringUtils.isNotEmpty(authData.getBPK())
+ && matchsReceivedbPKToOnlineApplication(pendingReq.getServiceProviderConfiguration(), authData.getBPKType()) ) {
+ log.debug("Correct bPK is already included in AuthData.");
+
+ //check if bPK received by PVP-Attribute matches OA
+ } else if (StringUtils.isNotEmpty(pvpbPKValue) &&
+ matchsReceivedbPKToOnlineApplication(pendingReq.getServiceProviderConfiguration(), pvpbPKTypeAttr)) {
+ log.debug("Receive correct bPK from PVP-Attribute");
+ authData.setBPK(pvpbPKValue);
+ authData.setBPKType(pvpbPKTypeAttr);
+
+ //check if decrypted bPK exists
+ } else if (pvpEncbPKAttr != null) {
+ log.debug("Receive bPK as encrypted bPK and decryption was possible.");
+ authData.setBPK(pvpEncbPKAttr.getFirst());
+ authData.setBPKType(pvpEncbPKAttr.getSecond());
+
+ //ask SZR to get bPK
+ } else {
+ String notValidbPK = authData.getBPK();
+ String notValidbPKType = authData.getBPKType();
+ if (StringUtils.isEmpty(notValidbPK) &&
+ StringUtils.isEmpty(notValidbPKType)) {
+ notValidbPK = pvpbPKValue;
+ notValidbPKType = pvpbPKTypeAttr;
+
+ if (StringUtils.isEmpty(notValidbPK) &&
+ StringUtils.isEmpty(notValidbPKType)) {
+ log.error("No bPK in MOASession. THIS error should not occur any more.");
+ throw new NullPointerException("No bPK in MOASession. THIS error should not occur any more.");
+ }
+ }
+
+ Pair<String, String> baseIDFromSZR = getbaseIDFromSZR(authData, notValidbPK, notValidbPKType);
+ if (baseIDFromSZR != null) {
+ log.info("Receive citizen baseID from SRZ. Authentication can be completed");
+ authData.setIdentificationValue(baseIDFromSZR.getFirst());
+ authData.setIdentificationType(baseIDFromSZR.getSecond());
+ Pair<String, String> result = buildOAspecificbPK(pendingReq, authData);
+ authData.setBPK(result.getFirst());
+ authData.setBPKType(result.getSecond());
+
+ } else {
+ log.warn("Can not build authData, because moaSession include no valid bPK, encrypted bPK or baseID");
+ throw new EAAFBuilderException("builder.08", new Object[]{"No valid " + PVPAttributeDefinitions.BPK_FRIENDLY_NAME
+ + " or " + PVPAttributeDefinitions.EID_SOURCE_PIN_FRIENDLY_NAME
+ + " or " + PVPAttributeDefinitions.ENC_BPK_LIST_FRIENDLY_NAME},
+ "No valid " + PVPAttributeDefinitions.BPK_FRIENDLY_NAME
+ + " or " + PVPAttributeDefinitions.EID_SOURCE_PIN_FRIENDLY_NAME
+ + " or " + PVPAttributeDefinitions.ENC_BPK_LIST_FRIENDLY_NAME);
+
+ }
+ }
+
+ //build IdentityLink
+ if (authProcessData.getIdentityLink() != null)
+ authData.setIdentityLink(buildOAspecificIdentityLink(
+ pendingReq.getServiceProviderConfiguration(),
+ authProcessData.getIdentityLink(),
+ authData.getBPK(),
+ authData.getBPKType()));
+ else
+ log.info("Can NOT set IdentityLink. Msg: No IdentityLink found");
+
+ }
+
+ //extract a encrypted bPK from PVP attrobute
+ protected abstract Pair<String, String> getEncryptedbPKFromPVPAttribute(IAuthProcessDataContainer authProcessDataContainer,
+ AuthenticationData authData, ISPConfiguration spConfig) throws EAAFBuilderException;
+
+ //request baseId from SRZ
+ protected abstract Pair<String, String> getbaseIDFromSZR(AuthenticationData authData, String notValidbPK,
+ String notValidbPKType);
+
+
+ protected Pair<String, String> buildOAspecificbPK(IRequest pendingReq, AuthenticationData authData) throws EAAFBuilderException {
+ ISPConfiguration oaParam = pendingReq.getServiceProviderConfiguration();
+
+ String baseID = authData.getIdentificationValue();
+ String baseIDType = authData.getIdentificationType();
+ Pair<String, String> sectorSpecId = null;
+
+ if (EAAFConstants.URN_PREFIX_BASEID.equals(baseIDType)) {
+ //SAML1 legacy target parameter work-around
+ String spTargetId = oaParam.getAreaSpecificTargetIdentifier();
+ log.debug("Use OA target identifier '" + spTargetId + "' from configuration");
+
+ //calculate sector specific unique identifier
+ sectorSpecId = new BPKBuilder().generateAreaSpecificPersonIdentifier(baseID, spTargetId);
+
+ } else {
+ log.error("!!!baseID-element does not include a baseID. This should not be happen any more!!!");
+ sectorSpecId = Pair.newInstance(baseID, baseIDType);
+
+ }
+
+ log.trace("Authenticate user with bPK:" + sectorSpecId.getFirst() + " Type:" + sectorSpecId.getSecond());
+ return sectorSpecId;
+
+ }
+
+ protected IIdentityLink buildOAspecificIdentityLink(ISPConfiguration spConfig, IIdentityLink idl, String bPK, String bPKType) throws EAAFConfigurationException, XPathException, DOMException, EAAFParserException {
+ if (spConfig.hasBaseIdTransferRestriction()) {
+ log.debug("SP: " + spConfig.getUniqueIdentifier() + " has baseId transfer restriction. Remove baseId from IDL ...");
+ Element idlassertion = idl.getSamlAssertion();
+ //set bpk/wpbk;
+ Node prIdentification = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_IDENT_VALUE_XPATH);
+ prIdentification.getFirstChild().setNodeValue(bPK);
+ //set bkp/wpbk type
+ Node prIdentificationType = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_IDENT_TYPE_XPATH);
+ prIdentificationType.getFirstChild().setNodeValue(bPKType);
+
+ SimpleIdentityLinkAssertionParser idlparser = new SimpleIdentityLinkAssertionParser(idlassertion);
+ return idlparser.parseIdentityLink();
+
+ } else
+ return idl;
+
+ }
+
+ /**
+ * Check a bPK-Type against a Service-Provider configuration <br>
+ * If bPK-Type is <code>null</code> the result is <code>false</code>.
+ *
+ * @param oaParam Service-Provider configuration, never null
+ * @param bPKType bPK-Type to check
+ * @return true, if bPK-Type matchs to Service-Provider configuration, otherwise false
+ */
+ private boolean matchsReceivedbPKToOnlineApplication(ISPConfiguration oaParam, String bPKType) {
+ return oaParam.getAreaSpecificTargetIdentifier().equals(bPKType);
+
+ }
+
+ /**
+ * Parse information from an IdentityLink into AuthData object
+ *
+ * @param authData
+ * @param identityLink
+ * @param includedGenericSessionData
+ */
+ private void parseBasicUserInfosFromIDL(AuthenticationData authData, IIdentityLink identityLink, Collection<String> includedGenericSessionData) {
+ authData.setIdentificationValue(identityLink.getIdentificationValue());
+ authData.setIdentificationType(identityLink.getIdentificationType());
+
+ authData.setGivenName(identityLink.getGivenName());
+ authData.setFamilyName(identityLink.getFamilyName());
+ authData.setDateOfBirth(identityLink.getDateOfBirth());
+
+ //remove corresponding keys from genericSessionData if exists
+ includedGenericSessionData.remove(PVPAttributeDefinitions.PRINCIPAL_NAME_NAME);
+ includedGenericSessionData.remove(PVPAttributeDefinitions.GIVEN_NAME_NAME);
+ includedGenericSessionData.remove(PVPAttributeDefinitions.BIRTHDATE_NAME);
+ includedGenericSessionData.remove(PVPAttributeDefinitions.EID_SOURCE_PIN_NAME);
+ includedGenericSessionData.remove(PVPAttributeDefinitions.EID_SOURCE_PIN_TYPE_NAME);
+
+ }
+
+ /**
+ * Get bPK from PVP Attribute 'BPK_NAME', which could be exist in
+ * MOASession as 'GenericData' <br> <pre><code>session.getGenericDataFromSession(PVPConstants.BPK_NAME, String.class)</code></pre>
+ *
+ * @param session MOASession, but never null
+ * @return bPK, which was received by PVP-Attribute, or <code>null</code> if no attribute exists
+ */
+ private String getbPKValueFromPVPAttribute(IAuthProcessDataContainer session) {
+ String pvpbPKValueAttr = session.getGenericDataFromSession(PVPAttributeDefinitions.BPK_NAME, String.class);
+ if (StringUtils.isNotEmpty(pvpbPKValueAttr)) {
+
+ //fix a wrong bPK-value prefix, which was used in some PVP Standardportal implementations
+ if (pvpbPKValueAttr.startsWith("bPK:")) {
+ log.warn("Attribute " + PVPAttributeDefinitions.BPK_NAME
+ + " contains a not standardize prefix! Staring attribute value correction process ...");
+ pvpbPKValueAttr = pvpbPKValueAttr.substring("bPK:".length());
+
+ }
+
+ String[] spitted = pvpbPKValueAttr.split(":");
+ if (spitted.length != 2) {
+ log.warn("Attribute " + PVPAttributeDefinitions.BPK_NAME + " has a wrong encoding and can NOT be USED!"
+ + " Value:" + pvpbPKValueAttr);
+ return null;
+
+ }
+ log.debug("Find PVP-Attr: " + PVPAttributeDefinitions.BPK_FRIENDLY_NAME);
+ return spitted[1];
+
+ }
+
+ return null;
+ }
+
+ /**
+ * Get bPK-Type from PVP Attribute 'EID_SECTOR_FOR_IDENTIFIER_NAME', which could be exist in
+ * MOASession as 'GenericData' <br> <pre><code>session.getGenericDataFromSession(PVPConstants.EID_SECTOR_FOR_IDENTIFIER_NAME, String.class)</code></pre>
+ *
+ * @param session MOASession, but never null
+ * @return bPKType, which was received by PVP-Attribute, or <code>null</code> if no attribute exists
+ */
+ private String getbPKTypeFromPVPAttribute(IAuthProcessDataContainer session) {
+ String pvpbPKTypeAttr = session.getGenericDataFromSession(PVPAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME, String.class);
+ if (StringUtils.isNotEmpty(pvpbPKTypeAttr)) {
+
+ //fix a wrong bPK-Type encoding, which was used in some PVP Standardportal implementations
+ if (pvpbPKTypeAttr.startsWith(EAAFConstants.URN_PREFIX_CDID) &&
+ !pvpbPKTypeAttr.substring(EAAFConstants.URN_PREFIX_CDID.length(),
+ EAAFConstants.URN_PREFIX_CDID.length() + 1).equals("+")) {
+ log.warn("Receive uncorrect encoded bBKType attribute " + pvpbPKTypeAttr + " Starting attribute value correction ... ");
+ pvpbPKTypeAttr = EAAFConstants.URN_PREFIX_CDID + "+" + pvpbPKTypeAttr.substring(EAAFConstants.URN_PREFIX_CDID.length() + 1);
+
+ }
+ log.debug("Find PVP-Attr: " + PVPAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_FRIENDLY_NAME);
+ return pvpbPKTypeAttr;
+ }
+
+ return null;
+
+
+ /*
+ * INFO: This code could be used to extract the bPKType from 'PVPConstants.BPK_NAME',
+ * because the prefix of BPK_NAME attribute contains the postfix of the bPKType
+ *
+ * Now, all PVP Standardportals should be able to send 'EID_SECTOR_FOR_IDENTIFIER'
+ * PVP attributes
+ */
+// String pvpbPKValueAttr = session.getGenericDataFromSession(PVPConstants.BPK_NAME, String.class);
+// String[] spitted = pvpbPKValueAttr.split(":");
+// if (MiscUtil.isEmpty(authData.getBPKType())) {
+// Logger.debug("PVP assertion contains NO bPK/wbPK target attribute. " +
+// "Starting target extraction from bPK/wbPK prefix ...");
+// //exract bPK/wbPK type from bpk attribute value prefix if type is
+// //not transmitted as single attribute
+// Pattern pattern = Pattern.compile("[a-zA-Z]{2}(-[a-zA-Z]+)?");
+// Matcher matcher = pattern.matcher(spitted[0]);
+// if (matcher.matches()) {
+// //find public service bPK
+// authData.setBPKType(Constants.URN_PREFIX_CDID + "+" + spitted[0]);
+// Logger.debug("Found bPK prefix. Set target to " + authData.getBPKType());
+//
+// } else {
+// //find business service wbPK
+// authData.setBPKType(Constants.URN_PREFIX_WBPK+ "+" + spitted[0]);
+// Logger.debug("Found wbPK prefix. Set target to " + authData.getBPKType());
+//
+// }
+// }
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/BPKBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/BPKBuilder.java
new file mode 100644
index 00000000..62a57dd1
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/BPKBuilder.java
@@ -0,0 +1,302 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ ******************************************************************************/
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
+
+package at.gv.egiz.eaaf.core.impl.idp.auth.builder;
+
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.Base64Utils;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.exceptions.EAAFBuilderException;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+
+/**
+ * Builder for the bPK, as defined in
+ * <code>&quot;Ableitung f&uml;r die bereichsspezifische Personenkennzeichnung&quot;</code>
+ * version <code>1.0.1</code> from <code>&quot;reference.e-government.gv.at&quot;</code>.
+ *
+ */
+public class BPKBuilder {
+ private static final Logger log = LoggerFactory.getLogger(BPKBuilder.class);
+
+ /**
+ * Calculates an area specific unique person-identifier from a baseID
+ *
+ * @param baseID baseId from user but never null
+ * @param targetIdentifier target identifier for area specific identifier calculation but never null
+ * @return Pair<unique person identifier for this target, targetArea> but never null
+ * @throws EAAFBuilderException if some input data are not valid
+ */
+ public Pair<String, String> generateAreaSpecificPersonIdentifier(String baseID, String targetIdentifier) throws EAAFBuilderException {
+ return generateAreaSpecificPersonIdentifier(baseID, EAAFConstants.URN_PREFIX_BASEID, targetIdentifier);
+
+ }
+
+ /**
+ * Calculates an area specific unique person-identifier from an unique identifier with a specific type
+ *
+ * @param baseID baseId from user but never null
+ * @param baseIdType Type of the baseID but never null
+ * @param targetIdentifier target identifier for area specific identifier calculation but never null
+ * @return Pair<unique person identifier for this target, targetArea> but never null
+ * @throws EAAFBuilderException if some input data are not valid
+ */
+ public Pair<String, String> generateAreaSpecificPersonIdentifier(String baseID, String baseIdType, String targetIdentifier) throws EAAFBuilderException{
+ if (StringUtils.isEmpty(baseID))
+ throw new EAAFBuilderException("builder.00", new Object[]{"baseID is empty or null"},
+ "BaseId is empty or null");
+
+ if (StringUtils.isEmpty(baseIdType))
+ throw new EAAFBuilderException("builder.00", new Object[]{"the type of baseID is empty or null"},
+ "Type of baseId is empty or null");
+
+ if (StringUtils.isEmpty(targetIdentifier))
+ throw new EAAFBuilderException("builder.00", new Object[]{"SP specific target identifier is empty or null"},
+ "SP specific target identifier is empty or null");
+
+ if (baseIdType.equals(EAAFConstants.URN_PREFIX_BASEID)) {
+ log.trace("Find baseID. Starting unique identifier caluclation for this target");
+
+ if (targetIdentifier.startsWith(EAAFConstants.URN_PREFIX_CDID) ||
+ targetIdentifier.startsWith(EAAFConstants.URN_PREFIX_WBPK)) {
+ log.trace("Calculate bPK, wbPK, or STORK identifier for target: " + targetIdentifier);
+ return Pair.newInstance(calculatebPKwbPK(baseID + "+" + targetIdentifier), targetIdentifier);
+
+ } else if (targetIdentifier.startsWith(EAAFConstants.URN_PREFIX_EIDAS)) {
+ log.trace("Calculate eIDAS identifier for target: " + targetIdentifier);
+ String[] splittedTarget = targetIdentifier.split("\\+");
+ String cititzenCountryCode = splittedTarget[1];
+ String eIDASOutboundCountry = splittedTarget[2];
+
+ if (cititzenCountryCode.equalsIgnoreCase(eIDASOutboundCountry)) {
+ log.warn("Suspect configuration FOUND!!! CitizenCountry equals DestinationCountry");
+
+ }
+ return buildeIDASIdentifer(baseID, baseIdType, cititzenCountryCode, eIDASOutboundCountry);
+
+
+ } else
+ throw new EAAFBuilderException("builder.00",
+ new Object[]{"Target identifier: " + targetIdentifier + " is NOT allowed or unknown"},
+ "Target identifier: " + targetIdentifier + " is NOT allowed or unknown");
+
+ } else {
+ log.trace("BaseID is not of type " + EAAFConstants.URN_PREFIX_BASEID + ". Check type against requested target ...");
+ if (baseIdType.equals(targetIdentifier)) {
+ log.debug("Unique identifier is already area specific. Is nothing todo");
+ return Pair.newInstance(baseID, targetIdentifier);
+
+ } else {
+ log.warn("Get unique identifier for target: " + baseIdType + " but target: " + targetIdentifier + " is required!");
+ throw new EAAFBuilderException("builder.00",
+ new Object[]{"Get unique identifier for target: " + baseIdType + " but target: " + targetIdentifier + " is required"},
+ "Get unique identifier for target: " + baseIdType + " but target: " + targetIdentifier + " is required");
+
+ }
+ }
+ }
+
+
+ /**
+ * Builds the eIDAS from the given parameters.
+ *
+ * @param baseID baseID of the citizen
+ * @param baseIDType Type of the baseID
+ * @param sourceCountry CountryCode of that country, which build the eIDAs ID
+ * @param destinationCountry CountryCode of that country, which receives the eIDAs ID
+ *
+ * @return Pair<eIDAs, bPKType> in a BASE64 encoding
+ * @throws EAAFBuilderException if some input data are not valid
+ */
+ private Pair<String, String> buildeIDASIdentifer(String baseID, String baseIDType, String sourceCountry, String destinationCountry)
+ throws EAAFBuilderException {
+ String bPK = null;
+ String bPKType = null;
+
+ // check if we have been called by public sector application
+ if (baseIDType.startsWith(EAAFConstants.URN_PREFIX_BASEID)) {
+ bPKType = EAAFConstants.URN_PREFIX_EIDAS + "+" + sourceCountry + "+" + destinationCountry;
+ log.debug("Building eIDAS identification from: [identValue]+" + bPKType);
+ bPK = calculatebPKwbPK(baseID + "+" + bPKType);
+
+ } else { // if not, sector identification value is already calculated by BKU
+ log.debug("eIDAS eIdentifier already provided by BKU");
+ bPK = baseID;
+ }
+
+ if ((StringUtils.isEmpty(bPK) ||
+ StringUtils.isEmpty(sourceCountry) ||
+ StringUtils.isEmpty(destinationCountry))) {
+ throw new EAAFBuilderException("builder.00",
+ new Object[]{"eIDAS-ID", "Unvollständige Parameterangaben: identificationValue=" +
+ bPK + ", Zielland=" + destinationCountry + ", Ursprungsland=" + sourceCountry}
+ ,"eIDAS-ID: Unvollständige Parameterangaben: identificationValue=" +
+ bPK + ", Zielland=" + destinationCountry + ", Ursprungsland=" + sourceCountry);
+ }
+
+ log.debug("Building eIDAS identification from: " + sourceCountry+"/"+destinationCountry+"/" + "[identValue]");
+ String eIdentifier = sourceCountry + "/" + destinationCountry + "/" + bPK;
+
+ return Pair.newInstance(eIdentifier, bPKType);
+ }
+
+ public static String encryptBPK(String bpk, String target, PublicKey publicKey) throws EAAFBuilderException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ if (target.startsWith(EAAFConstants.URN_PREFIX_CDID + "+"))
+ target = target.substring((EAAFConstants.URN_PREFIX_CDID + "+").length());
+
+ String input = "V1::urn:publicid:gv.at:cdid+" + target + "::"
+ + bpk + "::"
+ + sdf.format(new Date());
+ System.out.println(input);
+ byte[] result;
+ try {
+ byte[] inputBytes = input.getBytes("ISO-8859-1");
+ result = encrypt(inputBytes, publicKey);
+ return new String(Base64Utils.encode(result), "ISO-8859-1").replaceAll("\r\n", "");
+ //return new String(Base64Utils.encode(result, "ISO-8859-1")).replaceAll("\r\n", "");
+
+
+ } catch (Exception e) {
+ throw new EAAFBuilderException("bPK encryption FAILED", null,
+ e.getMessage(), e);
+
+ }
+ }
+
+ public static String decryptBPK(String encryptedBpk, String target, PrivateKey privateKey) throws EAAFBuilderException {
+ String decryptedString;
+ try {
+ //byte[] encryptedBytes = Base64Utils.decode(encryptedBpk, false, "ISO-8859-1");
+ byte[] encryptedBytes = Base64Utils.decode(encryptedBpk.getBytes("ISO-8859-1"));
+ byte[] decryptedBytes = decrypt(encryptedBytes, privateKey);
+ decryptedString = new String(decryptedBytes, "ISO-8859-1");
+
+ } catch (Exception e) {
+ throw new EAAFBuilderException("bPK decryption FAILED", null,
+ e.getMessage(), e);
+
+ }
+
+ String tmp = decryptedString.substring(decryptedString.indexOf('+') + 1);
+ String sector = tmp.substring(0, tmp.indexOf("::"));
+ tmp = tmp.substring(tmp.indexOf("::") + 2);
+ String bPK = tmp.substring(0, tmp.indexOf("::"));
+
+ if (target.startsWith(EAAFConstants.URN_PREFIX_CDID + "+"))
+ target = target.substring((EAAFConstants.URN_PREFIX_CDID + "+").length());
+
+ if (target.equals(sector))
+ return bPK;
+
+ else {
+ log.error("Decrypted bPK does not match to request bPK target.");
+ return null;
+ }
+ }
+
+ private String calculatebPKwbPK(String basisbegriff) throws EAAFBuilderException {
+ try {
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] hash = md.digest(basisbegriff.getBytes("ISO-8859-1"));
+ String hashBase64 = new String(Base64Utils.encode(hash), "ISO-8859-1").replaceAll("\r\n", ""); //Base64Utils.encode(hash);
+ return hashBase64;
+
+ } catch (Exception ex) {
+ throw new EAAFBuilderException("builder.00", new Object[]{"bPK/wbPK", ex.toString()},
+ ex.getMessage(), ex);
+
+ }
+
+ }
+
+ private static byte[] encrypt(byte[] inputBytes, PublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
+ byte[] result;
+ Cipher cipher = null;
+ try {
+ cipher = Cipher.getInstance("RSA/ECB/OAEPPadding"); // try with bouncycastle
+
+ } catch(NoSuchAlgorithmException e) {
+ cipher = Cipher.getInstance("RSA/ECB/OAEP"); // try with iaik provider
+ }
+ cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+ result = cipher.doFinal(inputBytes);
+
+ return result;
+ }
+
+ private static byte[] decrypt(byte[] encryptedBytes, PrivateKey privateKey)
+ throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
+ byte[] result;
+ Cipher cipher = null;
+ try {
+ cipher = Cipher.getInstance("RSA/ECB/OAEPPadding"); // try with bouncycastle
+
+ } catch(NoSuchAlgorithmException e) {
+ cipher = Cipher.getInstance("RSA/ECB/OAEP"); // try with iaik provider
+
+ }
+ cipher.init(Cipher.DECRYPT_MODE, privateKey);
+ result = cipher.doFinal(encryptedBytes);
+ return result;
+
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/AuthProcessDataWrapper.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/AuthProcessDataWrapper.java
new file mode 100644
index 00000000..3fca5300
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/AuthProcessDataWrapper.java
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.auth.data;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.idp.EAAFAuthProcessDataConstants;
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IAuthProcessDataContainer;
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException;
+
+public class AuthProcessDataWrapper implements IAuthProcessDataContainer, EAAFAuthProcessDataConstants {
+ private static final Logger log = LoggerFactory.getLogger(AuthProcessDataWrapper.class);
+
+ protected Map<String, Object> authProcessData;
+
+ public AuthProcessDataWrapper(Map<String, Object> authProcessData) {
+ this.authProcessData = authProcessData;
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#getIssueInstant()
+ */
+ @Override
+ public String getIssueInstant() {
+ return wrapStringObject(VALUE_ISSUEINSTANT, null, String.class);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#setIssueInstant(java.lang.String)
+ */
+ @Override
+ public void setIssueInstant(String issueInstant) {
+ authProcessData.put(VALUE_ISSUEINSTANT, issueInstant);
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#isAuthenticated()
+ */
+ @Override
+ public boolean isAuthenticated() {
+ return wrapStringObject(FLAG_IS_AUTHENTICATED, false, Boolean.class);
+
+ }
+
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#setAuthenticated(boolean)
+ */
+ @Override
+ public void setAuthenticated(boolean authenticated) {
+ authProcessData.put(FLAG_IS_AUTHENTICATED, authenticated);
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#getIdentityLink()
+ */
+ @Override
+ public IIdentityLink getIdentityLink() {
+ return wrapStringObject(VALUE_IDENTITYLINK, null, IIdentityLink.class);
+
+ }
+
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#setIdentityLink(at.gv.egovernment.moa.id.auth.data.IdentityLink)
+ */
+ @Override
+ public void setIdentityLink(IIdentityLink identityLink) {
+ authProcessData.put(VALUE_IDENTITYLINK, identityLink);
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#isMandateUsed()
+ */
+ @Override
+ public boolean isMandateUsed() {
+ return wrapStringObject(FLAG_USE_MANDATE, false, Boolean.class);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#setUseMandates(boolean)
+ */
+ @Override
+ public void setUseMandates(boolean useMandates) {
+ authProcessData.put(FLAG_USE_MANDATE, useMandates);
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#getQAALevel()
+ */
+ @Override
+ public String getQAALevel() {
+ return wrapStringObject(VALUE_QAALEVEL, null, String.class);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#setQAALevel(java.lang.String)
+ */
+ @Override
+ public void setQAALevel(String qAALevel) {
+ authProcessData.put(VALUE_QAALEVEL, qAALevel);
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#isForeigner()
+ */
+ @Override
+ public boolean isForeigner() {
+ return wrapStringObject(FLAG_IS_FOREIGNER, false, Boolean.class);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#setForeigner(boolean)
+ */
+ @Override
+ public void setForeigner(boolean isForeigner) {
+ authProcessData.put(FLAG_IS_FOREIGNER, isForeigner);
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#isOW()
+ */
+ @Override
+ public boolean isOW() {
+ return wrapStringObject(FLAG_IS_ORGANWALTER, false, Boolean.class);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#setOW(boolean)
+ */
+ @Override
+ public void setOW(boolean isOW) {
+ authProcessData.put(FLAG_IS_ORGANWALTER, isOW);
+
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#getSessionCreated()
+ */
+ @Override
+ public Date getSessionCreated() {
+ return wrapStringObject(EAAFConstants.AUTH_DATA_CREATED, null, Date.class);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#getGenericSessionDataStorage()
+ */
+ @Override
+ public Map<String, Object> getGenericSessionDataStorage() {
+ Map<String, Object> result = new HashMap<String, Object>();
+ for (String el : authProcessData.keySet()) {
+ if (el.startsWith(GENERIC_PREFIX))
+ result.put(el.substring(GENERIC_PREFIX.length()), authProcessData.get(el));
+
+ }
+
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#getGenericDataFromSession(java.lang.String)
+ */
+ @Override
+ public Object getGenericDataFromSession(String key) {
+ return authProcessData.get(GENERIC_PREFIX + key);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#getGenericDataFromSession(java.lang.String, java.lang.Class)
+ */
+ @Override
+ public <T> T getGenericDataFromSession(String key, Class<T> clazz) {
+ return wrapStringObject(GENERIC_PREFIX + key, null, clazz);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IAuthenticationSession#setGenericDataToSession(java.lang.String, java.lang.Object)
+ */
+ @Override
+ public void setGenericDataToSession(String key, Object object) throws EAAFStorageException {
+ authProcessData.put(GENERIC_PREFIX + key, object);
+
+ }
+
+ protected <T> T wrapStringObject(String key, Object defaultValue, Class<T> clazz) {
+ if (StringUtils.isNotEmpty(key)) {
+ Object obj = authProcessData.get(key);
+ if (obj != null && clazz.isInstance(obj))
+ return (T) obj;
+ }
+
+ if (defaultValue == null)
+ return null;
+
+ else if (clazz.isInstance(defaultValue))
+ return (T)defaultValue;
+
+ else {
+ log.error("DefaultValue: " + defaultValue.getClass().getName() + " is not of Type:" + clazz.getName());
+ throw new IllegalStateException("DefaultValue: " + defaultValue.getClass().getName() + " is not of Type:" + clazz.getName());
+
+ }
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/IdentityLink.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/IdentityLink.java
new file mode 100644
index 00000000..becd630e
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/IdentityLink.java
@@ -0,0 +1,312 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ ******************************************************************************/
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
+
+package at.gv.egiz.eaaf.core.impl.idp.auth.data;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.security.PublicKey;
+
+import javax.xml.transform.TransformerException;
+
+import org.w3c.dom.Element;
+
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+import at.gv.egiz.eaaf.core.impl.utils.DOMUtils;
+
+
+/**
+ * Data contained in an identity link issued by BMI, relevant to the MOA ID component.
+ * <br><code>"IdentityLink"</code> is the translation of <code>"Personenbindung"</code>.
+ *
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class IdentityLink implements Serializable, IIdentityLink{
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * <code>"identificationValue"</code> is the translation of <code>"Stammzahl"</code>.
+ */
+ private String identificationValue;
+ /**
+ * <code>"identificationType"</code> type of the identificationValue in the IdentityLink.
+ */
+ private String identificationType;
+ /**
+ * first name
+ */
+ private String givenName;
+ /**
+ * family name
+ */
+ private String familyName;
+
+ /**
+ * The name as (givenName + familyName)
+ */
+ private String name;
+ /**
+ * date of birth
+ */
+ private String dateOfBirth;
+ /**
+ * the original saml:Assertion-Element
+ */
+ private Element samlAssertion;
+ /**
+ * the serializes saml:Assertion
+ */
+ private String serializedSamlAssertion;
+ /**
+ * Element /saml:Assertion/saml:AttributeStatement/saml:Subject/saml:SubjectConfirmation/saml:SubjectConfirmationData/pr:Person
+ */
+ private Element prPerson;
+ /**
+ * we need for each dsig:Reference Element all
+ * transformation elements
+ */
+ private Element[] dsigReferenceTransforms;
+
+ /**
+ * The issuing time of the identity link SAML assertion.
+ */
+ private String issueInstant;
+
+ /**
+ * we need all public keys stored in
+ * the identity link
+ */
+ private PublicKey[] publicKey;
+
+ /**
+ * Constructor for IdentityLink
+ */
+ public IdentityLink() {
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getDateOfBirth()
+ */
+ @Override
+public String getDateOfBirth() {
+ return dateOfBirth;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getFamilyName()
+ */
+ @Override
+public String getFamilyName() {
+ return familyName;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getGivenName()
+ */
+ @Override
+public String getGivenName() {
+ return givenName;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getName()
+ */
+ @Override
+public String getName() {
+ if (name == null) {
+ name = givenName + " " + familyName;
+ }
+ return name;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getIdentificationValue()
+ */
+ @Override
+public String getIdentificationValue() {
+ return identificationValue;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getIdentificationType()
+ */
+ @Override
+ public String getIdentificationType() {
+ return identificationType;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#setDateOfBirth(java.lang.String)
+ */
+ @Override
+public void setDateOfBirth(String dateOfBirth) {
+ this.dateOfBirth = dateOfBirth;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#setFamilyName(java.lang.String)
+ */
+ @Override
+public void setFamilyName(String familyName) {
+ this.familyName = familyName;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#setGivenName(java.lang.String)
+ */
+ @Override
+public void setGivenName(String givenName) {
+ this.givenName = givenName;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#setIdentificationValue(java.lang.String)
+ */
+ @Override
+public void setIdentificationValue(String identificationValue) {
+ this.identificationValue = identificationValue;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#setIdentificationType(java.lang.String)
+ */
+ @Override
+ public void setIdentificationType(String identificationType) {
+ this.identificationType = identificationType;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getSamlAssertion()
+ */
+ @Override
+public Element getSamlAssertion() {
+ return samlAssertion;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getSerializedSamlAssertion()
+ */
+ @Override
+public String getSerializedSamlAssertion() {
+ return serializedSamlAssertion;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#setSamlAssertion(org.w3c.dom.Element)
+ */
+ @Override
+public void setSamlAssertion(Element samlAssertion) throws TransformerException, IOException {
+ this.samlAssertion = samlAssertion;
+ this.serializedSamlAssertion = DOMUtils.serializeNode(samlAssertion);
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getDsigReferenceTransforms()
+ */
+ @Override
+public Element[] getDsigReferenceTransforms() {
+ return dsigReferenceTransforms;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#setDsigReferenceTransforms(org.w3c.dom.Element[])
+ */
+ @Override
+public void setDsigReferenceTransforms(Element[] dsigReferenceTransforms) {
+ this.dsigReferenceTransforms = dsigReferenceTransforms;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getPublicKey()
+ */
+ @Override
+public PublicKey[] getPublicKey() {
+ return publicKey;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#setPublicKey(java.security.PublicKey[])
+ */
+ @Override
+public void setPublicKey(PublicKey[] publicKey) {
+ this.publicKey = publicKey;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getPrPerson()
+ */
+ @Override
+public Element getPrPerson() {
+ return prPerson;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#setPrPerson(org.w3c.dom.Element)
+ */
+ @Override
+public void setPrPerson(Element prPerson) {
+ this.prPerson = prPerson;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#getIssueInstant()
+ */
+ @Override
+public String getIssueInstant() {
+ return issueInstant;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.data.IIdentityLink#setIssueInstant(java.lang.String)
+ */
+ @Override
+public void setIssueInstant(String issueInstant) {
+ this.issueInstant = issueInstant;
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/SimpleIdentityLinkAssertionParser.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/SimpleIdentityLinkAssertionParser.java
new file mode 100644
index 00000000..7fb5e642
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/SimpleIdentityLinkAssertionParser.java
@@ -0,0 +1,326 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ ******************************************************************************/
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
+
+package at.gv.egiz.eaaf.core.impl.idp.auth.data;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.util.Base64Utils;
+import org.w3c.dom.Element;
+import org.w3c.dom.traversal.NodeIterator;
+
+import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants;
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+import at.gv.egiz.eaaf.core.exceptions.EAAFParserException;
+import at.gv.egiz.eaaf.core.impl.utils.DOMUtils;
+import at.gv.egiz.eaaf.core.impl.utils.XPathUtils;
+
+/**
+ * Parses MDS from an identity link <code>&lt;saml:Assertion&gt;</code>
+ * <br>
+ * <b>This IDL parser extract NO key information!</b>
+
+ */
+public class SimpleIdentityLinkAssertionParser {
+
+ //
+ // XPath namespace prefix shortcuts
+ //
+
+ /** Xpath prefix for reaching PersonData Namespaces */
+ private static final String PDATA = XMLNamespaceConstants.PD_PREFIX + ":";
+ /** Xpath prefix for reaching SAML Namespaces */
+ private static final String SAML = XMLNamespaceConstants.SAML_PREFIX + ":";
+ /** Xpath prefix for reaching XML-DSIG Namespaces */
+ private static final String DSIG = XMLNamespaceConstants.DSIG_PREFIX + ":";
+ /** Xpath prefix for reaching ECDS Namespaces */
+ private static final String ECDSA = XMLNamespaceConstants.ECDSA_PREFIX + ":";
+ /** Xpath expression to the root element */
+ private static final String ROOT = "";
+ /** Xpath expression to the SAMLSubjectConfirmationData element */
+ private static final String SAML_SUBJECT_CONFIRMATION_DATA_XPATH =
+ ROOT
+ + SAML
+ + "AttributeStatement/"
+ + SAML
+ + "Subject/"
+ + SAML
+ + "SubjectConfirmation/"
+ + SAML
+ + "SubjectConfirmationData";
+ /** Xpath expression to the PersonData element */
+ private static final String PERSON_XPATH =
+ SAML_SUBJECT_CONFIRMATION_DATA_XPATH
+ + "/"
+ + PDATA
+ + "Person";
+ /** Xpath expression to the PersonData GivenName element */
+ public static final String PERSON_GIVEN_NAME_XPATH =
+ PERSON_XPATH
+ + "/"
+ + PDATA
+ + "Name/"
+ + PDATA
+ + "GivenName";
+ /** Xpath expression to the PersonData FamilyName element */
+ public static final String PERSON_FAMILY_NAME_XPATH =
+ PERSON_XPATH
+ + "/"
+ + PDATA
+ + "Name/"
+ + PDATA
+ + "FamilyName";
+ /** Xpath expression to the PersonData DateOfBirth element */
+ public static final String PERSON_DATE_OF_BIRTH_XPATH =
+ PERSON_XPATH
+ + "/"
+ + PDATA
+ + "DateOfBirth";
+ /** Xpath expression to the Identification element */
+ private static final String PERSON_IDENT_XPATH =
+ PERSON_XPATH
+ + "/"
+ + PDATA
+ + "Identification";
+
+ /** Xpath expression to the Identification Value element */
+ public static final String PERSON_IDENT_VALUE_XPATH =
+ PERSON_XPATH
+ + "/"
+ + PDATA
+ + "Identification/"
+ + PDATA
+ + "Value";
+
+ /** Xpath expression to the Identification Value element */
+ public static final String PERSON_IDENT_TYPE_XPATH =
+ PERSON_XPATH
+ + "/"
+ + PDATA
+ + "Identification/"
+ + PDATA
+ + "Type";
+
+ /** Xpath expression to the RSAKeyValue element */
+ private static final String RSA_KEY_VALUE_XPATH =
+ ROOT
+ + SAML
+ + "AttributeStatement/"
+ + SAML
+ + "Attribute/"
+ + SAML
+ + "AttributeValue/"
+ + DSIG
+ + "RSAKeyValue";
+
+ /** Xpath expression to the ECKeyValue element */
+ private static final String ECDSA_KEY_VALUE_XPATH =
+ ROOT
+ + SAML
+ + "AttributeStatement/"
+ + SAML
+ + "Attribute/"
+ + SAML
+ + "AttributeValue/"
+ + ECDSA
+ + "ECDSAKeyValue";
+
+
+ /** Xpath expression to the RSA Modulus element */
+ private static final String RSA_KEY_MODULUS_XPATH = DSIG + "Modulus";
+ /** Xpath expression to the RSA Exponent element */
+ private static final String RSA_KEY_EXPONENT_XPATH = DSIG + "Exponent";
+ /** Xpath expression to the DSIG X509Certificate element */
+ private static final String DSIG_CERTIFICATES_XPATH =
+ ROOT
+ + DSIG
+ + "Signature/"
+ + DSIG
+ + "KeyInfo/"
+ + DSIG
+ + "X509Data/"
+ + DSIG
+ + "X509Certificate";
+ /** Xpath expression to the DSIG Transforms element */
+ private static final String DSIG_REFERENCE_TRANSFORMATION_XPATH =
+ ROOT
+ + DSIG
+ + "Signature/"
+ + DSIG
+ + "SignedInfo/"
+ + DSIG
+ + "Reference/"
+ + DSIG
+ + "Transforms";
+
+ /** The IssueInstant attribute of the SAML assertion */
+ private static final String ISSUE_INSTANT_ATTR = "IssueInstant";
+
+ /**This is the root element of the XML-Document provided by the Security Layer Card*/
+ private Element assertionElem;
+
+ /**
+ * Constructor for <code>IdentityLinkAssertionParser</code>.
+ * A DOM-representation of the incoming String will be created
+ * @param xmlAssertion <code>&lt;saml:Assertion&gt;</code> as String
+ * @throws EAAFParserException on any parsing error
+ */
+ public SimpleIdentityLinkAssertionParser(String xmlAssertion) throws EAAFParserException {
+ try {
+ InputStream s = new ByteArrayInputStream(xmlAssertion.getBytes("UTF-8"));
+ assertionElem = DOMUtils.parseXmlValidating(s);
+
+ }
+ catch (Throwable t) {
+ throw new EAAFParserException("parser.01", new Object[] { t.toString()},
+ t.getMessage(), t);
+
+ }
+ }
+
+ /**
+ * Sets the <@link assertionElem>.
+ * @param xmlAssertion the assertion element
+ * @throws EAAFParserException on any parsing error
+ */
+ public SimpleIdentityLinkAssertionParser(Element xmlAssertion) throws EAAFParserException {
+ assertionElem = xmlAssertion;
+ }
+
+ /**
+ * Constructor for <code>IdentityLinkAssertionParser</code>.
+ * A DOM-representation of the incoming Inputstream will be created
+ * @param xmlAssertion <code>&lt;saml:Assertion&gt;</code> as InputStream
+ * @throws EAAFParserException on any parsing error
+ */
+ public SimpleIdentityLinkAssertionParser(InputStream xmlAssertion) throws EAAFParserException {
+ try {
+ assertionElem = DOMUtils.parseXmlValidating(xmlAssertion);
+
+ }
+ catch (Throwable t) {
+ throw new EAAFParserException("parser.01", new Object[] { t.toString() }, t.getMessage(), t);
+
+ }
+ }
+
+ /**
+ * Parses the identity link from the <code>&lt;saml:Assertion&gt;</code>
+ * @return Identity link
+ * @throws EAAFParserException on any parsing error
+ */
+
+ public IIdentityLink parseIdentityLink() throws EAAFParserException {
+ IIdentityLink identityLink;
+ try {
+ identityLink = new IdentityLink();
+ identityLink.setSamlAssertion(assertionElem);
+ identityLink.setIssueInstant(assertionElem.getAttribute(ISSUE_INSTANT_ATTR));
+ identityLink.setPrPerson((Element)
+ XPathUtils.selectSingleNode(assertionElem, PERSON_XPATH));
+ identityLink.setIdentificationValue(
+ XPathUtils.getElementValue(assertionElem, PERSON_IDENT_VALUE_XPATH, ""));
+ identityLink.setIdentificationType(
+ XPathUtils.getElementValue(assertionElem, PERSON_IDENT_TYPE_XPATH, ""));
+
+ String givenname = XPathUtils.getElementValue(assertionElem, PERSON_GIVEN_NAME_XPATH, "");
+ String familyname = XPathUtils.getElementValue(assertionElem, PERSON_FAMILY_NAME_XPATH, "");
+
+ // replace ' in name with &#39;
+ givenname = givenname.replaceAll("'", "&#39;");
+ familyname = familyname.replaceAll("'", "&#39;");
+
+ identityLink.setGivenName(givenname);
+ identityLink.setFamilyName(familyname);
+ identityLink.setDateOfBirth(
+ XPathUtils.getElementValue(assertionElem, PERSON_DATE_OF_BIRTH_XPATH, ""));
+ NodeIterator dsigRefTransforms =
+ XPathUtils.selectNodeIterator(assertionElem, DSIG_REFERENCE_TRANSFORMATION_XPATH);
+ List transElems = new ArrayList();
+ Element transformsElem;
+ while ((transformsElem = (Element) dsigRefTransforms.nextNode()) != null) {
+ transElems.add(transformsElem);
+ }
+ Element[] result = new Element[transElems.size()];
+ transElems.toArray(result);
+ identityLink.setDsigReferenceTransforms(result);
+
+ //identityLink.setPublicKey(getPublicKeys());
+
+ }
+ catch (Throwable t) {
+ throw new EAAFParserException("parser.01", new Object[] { t.toString() },
+ t.getMessage(), t);
+ }
+
+ return identityLink;
+ }
+
+ /**
+ * Parses a string array of decoded base64 certificates from
+ * the <code>&lt;InfoboxReadResponse&gt;</code> found in the dsig-signature
+ * @return String[] with raw-certificates from the dsig-signature keyinfo
+ * @throws Exception
+ */
+ public String[] getCertificates() throws Exception {
+ List certs = new ArrayList();
+ NodeIterator rsaIter =
+ XPathUtils.selectNodeIterator(assertionElem, DSIG_CERTIFICATES_XPATH);
+ Element certElem;
+ while ((certElem = (Element) rsaIter.nextNode()) != null) {
+ String content = DOMUtils.getText(certElem);
+ certs.add(new String(Base64Utils.decodeFromString(content)));
+
+ }
+ String[] result = new String[certs.size()];
+ certs.toArray(result);
+ return result;
+
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/AbstractAuthServletTask.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/AbstractAuthServletTask.java
new file mode 100644
index 00000000..a421ff67
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/AbstractAuthServletTask.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.auth.modules;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileItemFactory;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.lang3.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.IRequestStorage;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractAuthProtocolModulController;
+import at.gv.egiz.eaaf.core.impl.idp.process.springweb.AbstractTask;
+import at.gv.egiz.eaaf.core.impl.utils.DataURLBuilder;
+
+/**
+ * Task based counterpart to {@link AuthServlet}, providing the same utility methods (error handling, parameter parsing
+ * etc.).</p> The code has been taken from {@link AuthServlet}.
+ */
+public abstract class AbstractAuthServletTask extends AbstractTask {
+ private static final Logger log = LoggerFactory.getLogger(AbstractAuthServletTask.class);
+
+ @Autowired(required=true) protected IRequestStorage requestStoreage;
+ @Autowired(required=true) protected IConfiguration authConfig;
+
+ @Autowired protected IRevisionLogger revisionsLogger;
+
+ protected static final String ERROR_CODE_PARAM = "errorid";
+
+ protected IRequest pendingReq = null;
+
+ public abstract void execute(ExecutionContext executionContext, HttpServletRequest request,
+ HttpServletResponse response) throws TaskExecutionException;
+
+
+ protected final IRequest internalExecute(IRequest pendingReq, ExecutionContext executionContext, HttpServletRequest request,
+ HttpServletResponse response) throws TaskExecutionException {
+ //set pending-request object
+ this.pendingReq = pendingReq;
+
+ //execute task specific action
+ execute(executionContext, request, response);
+
+ //return pending-request object
+ return this.pendingReq;
+ }
+
+ /**
+ * Redirect the authentication process to protocol specific finalization endpoint.
+ *
+ * @param pendingReq Actually processed protocol specific authentication request
+ * @param httpResp
+ */
+ protected void performRedirectToProtocolFinialization(IRequest pendingReq, HttpServletResponse httpResp) {
+ performRedirectToItself(pendingReq, httpResp, AbstractAuthProtocolModulController.ENDPOINT_FINALIZEPROTOCOL);
+
+ }
+
+ /**
+ * Redirect the authentication process to IDP itself
+ *
+ * @param pendingReq Actually processed protocol specific authentication request
+ * @param httpResp
+ * @param idpEndPoint Servlet EndPoint that should receive the redirect
+ */
+ protected void performRedirectToItself(IRequest pendingReq, HttpServletResponse httpResp, String idpEndPoint) {
+ String redirectURL = new DataURLBuilder().buildDataURL(pendingReq.getAuthURL(),
+ idpEndPoint, pendingReq.getPendingRequestId());
+
+ httpResp.setContentType("text/html");
+ httpResp.setStatus(302);
+ httpResp.addHeader("Location", redirectURL);
+ log.debug("REDIRECT TO: " + redirectURL);
+
+ }
+
+
+ /**
+ * Parses the request input stream for parameters, assuming parameters are
+ * encoded UTF-8 (no standard exists how browsers should encode them).
+ *
+ * @param req
+ * servlet request
+ *
+ * @return mapping parameter name -> value
+ *
+ * @throws IOException
+ * if parsing request parameters fails.
+ *
+ * @throws FileUploadException
+ * if parsing request parameters fails.
+ */
+ protected Map<String, String> getParameters(HttpServletRequest req) throws IOException,
+ FileUploadException {
+
+ Map<String, String> parameters = new HashMap<String, String>();
+
+ if (ServletFileUpload.isMultipartContent(req)) {
+ // request is encoded as mulitpart/form-data
+ FileItemFactory factory = new DiskFileItemFactory();
+ ServletFileUpload upload = null;
+ upload = new ServletFileUpload(factory);
+ List items = null;
+ items = upload.parseRequest(req);
+ for (int i = 0; i < items.size(); i++) {
+ FileItem item = (FileItem) items.get(i);
+ if (item.isFormField()) {
+ // Process only form fields - no file upload items
+ parameters.put(item.getFieldName(), item.getString("UTF-8"));
+
+ //log requests on trace
+ if (log.isTraceEnabled()) {
+ String logString = item.getString("UTF-8");
+
+ // TODO use RegExp
+ String startS = "<pr:Identification><pr:Value>";
+ String endS = "</pr:Value><pr:Type>urn:publicid:gv.at:baseid</pr:Type>";
+ String logWithMaskedBaseid = logString;
+ int start = logString.indexOf(startS);
+ if (start > -1) {
+ int end = logString.indexOf(endS);
+ if (end > -1) {
+ logWithMaskedBaseid = logString.substring(0, start);
+ logWithMaskedBaseid += startS;
+ logWithMaskedBaseid += "xxxxxxxxxxxxxxxxxxxxxxxx";
+ logWithMaskedBaseid += logString.substring(end,
+ logString.length());
+ }
+ }
+
+ log.debug("Processed multipart/form-data request parameter: \nName: "
+ + item.getFieldName()
+ + "\nValue: "
+ + logWithMaskedBaseid);
+ }
+
+ }
+ }
+ }
+
+ else {
+ Iterator<Entry<String, String[]>> requestParamIt = req.getParameterMap().entrySet().iterator();
+ while (requestParamIt.hasNext()) {
+ Entry<String, String[]> entry = requestParamIt.next();
+ String key = entry.getKey();
+ String[] values = entry.getValue();
+ // take the last value from the value array since the legacy code above also does it this way
+ parameters.put(key, ArrayUtils.isEmpty(values) ? null : values[values.length-1]);
+ }
+
+ }
+
+ return parameters;
+ }
+
+ /**
+ * Reads bytes up to a delimiter, consuming the delimiter.
+ *
+ * @param in
+ * input stream
+ * @param delimiter
+ * delimiter character
+ * @return String constructed from the read bytes
+ * @throws IOException
+ */
+ protected String readBytesUpTo(InputStream in, char delimiter)
+ throws IOException {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ boolean done = false;
+ int b;
+ while (!done && (b = in.read()) >= 0) {
+ if (b == delimiter)
+ done = true;
+ else
+ bout.write(b);
+ }
+ return bout.toString();
+ }
+
+ /**
+ * Adds a parameter to a URL.
+ *
+ * @param url
+ * the URL
+ * @param paramname
+ * parameter name
+ * @param paramvalue
+ * parameter value
+ * @return the URL with parameter added
+ */
+ protected static String addURLParameter(String url, String paramname,
+ String paramvalue) {
+ String param = paramname + "=" + paramvalue;
+ if (url.indexOf("?") < 0)
+ return url + "?" + param;
+ else
+ return url + "&" + param;
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/ModuleRegistration.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/ModuleRegistration.java
new file mode 100644
index 00000000..cb4a055a
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/ModuleRegistration.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.auth.modules;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.io.Resource;
+
+import at.gv.egiz.eaaf.core.api.idp.auth.modules.AuthModule;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine;
+import at.gv.egiz.eaaf.core.impl.idp.process.ProcessDefinitionParserException;
+
+/**
+ * This class handles registering modules. The modules are detected either with
+ * the ServiceLoader mechanism or via Spring. All detected modules are ranked
+ * according to their priority.
+ */
+public class ModuleRegistration {
+
+ private static ModuleRegistration instance = new ModuleRegistration();
+
+ private List<AuthModule> priorizedModules = new ArrayList<>();
+
+ @Autowired
+ private ApplicationContext ctx;
+
+ @Autowired
+ private ProcessEngine processEngine;
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+ public static ModuleRegistration getInstance() {
+ return instance;
+ }
+
+ private ModuleRegistration() {
+ }
+
+ @PostConstruct
+ private void init() {
+ // load modules via the ServiceLoader
+ initServiceLoaderModules();
+
+ // load modules via Spring
+ initSpringModules();
+
+ // order modules according to their priority
+ sortModules();
+ }
+
+ /**
+ * Discovers modules which use the ServiceLoader mechanism.
+ */
+ private void initServiceLoaderModules() {
+ log.info("Looking for auth modules.");
+ ServiceLoader<AuthModule> loader = ServiceLoader.load(AuthModule.class);
+ Iterator<AuthModule> modules = loader.iterator();
+ while (modules.hasNext()) {
+ AuthModule module = modules.next();
+ log.info("Detected module {}", module.getClass().getName());
+ registerModuleProcessDefinitions(module);
+ priorizedModules.add(module);
+ }
+ }
+
+ /**
+ * Discovers modules which use Spring.
+ */
+ private void initSpringModules() {
+ log.debug("Discovering Spring modules.");
+ Map<String, AuthModule> modules = ctx.getBeansOfType(AuthModule.class);
+ for (AuthModule module : modules.values()) {
+ registerModuleProcessDefinitions(module);
+ priorizedModules.add(module);
+ }
+ }
+
+ /**
+ * Registers the resource uris for the module.
+ *
+ * @param module
+ * the module.
+ */
+ private void registerModuleProcessDefinitions(AuthModule module) {
+ for (String uri : module.getProcessDefinitions()) {
+ Resource resource = ctx.getResource(uri);
+ if (resource.isReadable()) {
+ log.info("Registering process definition '{}'.", uri);
+ try (InputStream processDefinitionInputStream = resource.getInputStream()) {
+ processEngine.registerProcessDefinition(processDefinitionInputStream);
+ } catch (IOException e) {
+ log.error("Process definition '{}' could NOT be read.", uri, e);
+ } catch (ProcessDefinitionParserException e) {
+ log.error("Error while parsing process definition '{}'", uri, e);
+ }
+ } else {
+ log.error("Process definition '{}' cannot be read.", uri);
+ }
+ }
+ }
+
+ /**
+ * Order the modules in descending order according to their priority.
+ */
+ private void sortModules() {
+ Collections.sort(priorizedModules, new Comparator<AuthModule>() {
+ @Override
+ public int compare(AuthModule thisAuthModule, AuthModule otherAuthModule) {
+ int thisOrder = thisAuthModule.getPriority();
+ int otherOrder = otherAuthModule.getPriority();
+ return (thisOrder < otherOrder ? 1 : (thisOrder == otherOrder ? 0 : -1));
+ }
+ });
+ }
+
+ /**
+ * Returns the process description id of the first process, in the highest ranked
+ * module, which is able to work with the given execution context.
+ *
+ * @param context
+ * the {@link ExecutionContext}.
+ * @return the process id or {@code null}
+ */
+ public String selectProcess(ExecutionContext context) {
+ for (AuthModule module : priorizedModules) {
+ String id = module.selectProcess(context);
+ if (StringUtils.isNotEmpty(id)) {
+ log.debug("Process with id '{}' selected, for context '{}'.", id, context);
+ return id;
+ }
+ }
+ log.info("No process is able to handle context '{}'.", context);
+ return null;
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BPKAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BPKAttributeBuilder.java
new file mode 100644
index 00000000..575f2beb
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BPKAttributeBuilder.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.builder.attributes;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IPVPAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException;
+
+public class BPKAttributeBuilder implements IPVPAttributeBuilder {
+
+ private static final Logger log = LoggerFactory.getLogger(BPKAttributeBuilder.class);
+
+ public String getName() {
+ return BPK_NAME;
+ }
+
+ public <ATT> ATT build(ISPConfiguration oaParam, IAuthData authData,
+ IAttributeGenerator<ATT> g) throws AttributeBuilderException {
+ String bpk = authData.getBPK();
+ String type = authData.getBPKType();
+
+ if (StringUtils.isEmpty(bpk))
+ throw new UnavailableAttributeException(BPK_NAME);
+
+ if (type.startsWith(EAAFConstants.URN_PREFIX_WBPK))
+ type = type.substring((EAAFConstants.URN_PREFIX_WBPK).length());
+
+ else if (type.startsWith(EAAFConstants.URN_PREFIX_CDID))
+ type = type.substring((EAAFConstants.URN_PREFIX_CDID).length());
+
+ else if (type.startsWith(EAAFConstants.URN_PREFIX_EIDAS))
+ type = type.substring((EAAFConstants.URN_PREFIX_EIDAS).length());
+
+ if (bpk.length() > BPK_MAX_LENGTH) {
+ bpk = bpk.substring(0, BPK_MAX_LENGTH);
+ }
+
+ log.trace("Authenticate user with bPK/wbPK " + bpk + " and Type=" + type);
+
+ return g.buildStringAttribute(BPK_FRIENDLY_NAME, BPK_NAME, type + ":" + bpk);
+ }
+
+ public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) {
+ return g.buildEmptyAttribute(BPK_FRIENDLY_NAME, BPK_NAME);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BirthdateAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BirthdateAttributeBuilder.java
new file mode 100644
index 00000000..cac7e3bf
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BirthdateAttributeBuilder.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.builder.attributes;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IPVPAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+
+public class BirthdateAttributeBuilder implements IPVPAttributeBuilder {
+
+ public String getName() {
+ return BIRTHDATE_NAME;
+ }
+
+ public <ATT> ATT build(ISPConfiguration oaParam, IAuthData authData,
+ IAttributeGenerator<ATT> g) throws AttributeBuilderException {
+
+ if (authData.getDateOfBirth() != null) {
+ DateFormat pvpDateFormat = new SimpleDateFormat(BIRTHDATE_FORMAT_PATTERN);
+ String dateString = pvpDateFormat.format(authData.getDateOfBirth());
+
+ return g.buildStringAttribute(BIRTHDATE_FRIENDLY_NAME, BIRTHDATE_NAME, dateString);
+
+ } else {
+ //build empty attribute if no Birthday date is found (STORK2)
+ return g.buildEmptyAttribute(BIRTHDATE_FRIENDLY_NAME, BIRTHDATE_NAME);
+
+ }
+ }
+
+ public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) {
+ return g.buildEmptyAttribute(BIRTHDATE_FRIENDLY_NAME, BIRTHDATE_NAME);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDIdentityLinkBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDIdentityLinkBuilder.java
new file mode 100644
index 00000000..f55353d2
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDIdentityLinkBuilder.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.builder.attributes;
+
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.Base64Utils;
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IPVPAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException;
+
+
+
+public class EIDIdentityLinkBuilder implements IPVPAttributeBuilder {
+ private static final Logger log = LoggerFactory.getLogger(EIDIdentityLinkBuilder.class);
+
+
+ public String getName() {
+ return EID_IDENTITY_LINK_NAME;
+ }
+
+ public <ATT> ATT build(ISPConfiguration oaParam, IAuthData authData,
+ IAttributeGenerator<ATT> g) throws AttributeBuilderException {
+ try {
+ String ilAssertion = null;
+ if (authData.getIdentityLink() == null)
+ throw new UnavailableAttributeException(EID_IDENTITY_LINK_NAME);
+
+ ilAssertion = authData.getIdentityLink().getSerializedSamlAssertion();
+
+ return g.buildStringAttribute(EID_IDENTITY_LINK_FRIENDLY_NAME,
+ EID_IDENTITY_LINK_NAME, Base64Utils.encodeToString(ilAssertion.getBytes("UTF-8")));
+
+
+ } catch (IOException e) {
+ log.warn("IdentityLink serialization error.", e);
+ return g.buildEmptyAttribute(EID_IDENTITY_LINK_FRIENDLY_NAME,
+ EID_IDENTITY_LINK_NAME);
+ }
+
+ }
+
+ public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) {
+ return g.buildEmptyAttribute(EID_IDENTITY_LINK_FRIENDLY_NAME,
+ EID_IDENTITY_LINK_NAME);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDIssuingNationAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDIssuingNationAttributeBuilder.java
new file mode 100644
index 00000000..9a038aa2
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDIssuingNationAttributeBuilder.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.builder.attributes;
+
+import org.apache.commons.lang3.StringUtils;
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IPVPAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+
+public class EIDIssuingNationAttributeBuilder implements IPVPAttributeBuilder {
+
+ public String getName() {
+ return EID_ISSUING_NATION_NAME;
+ }
+
+ public <ATT> ATT build(ISPConfiguration oaParam, IAuthData authData,
+ IAttributeGenerator<ATT> g) throws AttributeBuilderException {
+ String countryCode = authData.getCiticenCountryCode();
+ if (StringUtils.isNotEmpty(countryCode))
+ return g.buildStringAttribute(EID_ISSUING_NATION_FRIENDLY_NAME,
+ EID_ISSUING_NATION_NAME, countryCode);
+
+ else
+ return null;
+ }
+
+ public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) {
+ return g.buildEmptyAttribute(EID_ISSUING_NATION_FRIENDLY_NAME,
+ EID_ISSUING_NATION_NAME);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSectorForIDAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSectorForIDAttributeBuilder.java
new file mode 100644
index 00000000..c170a124
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSectorForIDAttributeBuilder.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.builder.attributes;
+
+import org.apache.commons.lang3.StringUtils;
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IPVPAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException;
+
+public class EIDSectorForIDAttributeBuilder implements IPVPAttributeBuilder {
+
+ public String getName() {
+ return EID_SECTOR_FOR_IDENTIFIER_NAME;
+ }
+
+ public <ATT> ATT build(ISPConfiguration oaParam, IAuthData authData,
+ IAttributeGenerator<ATT> g) throws AttributeBuilderException {
+ String bpktype = authData.getBPKType();
+
+ if (StringUtils.isEmpty(authData.getBPKType()))
+ throw new UnavailableAttributeException(EID_SECTOR_FOR_IDENTIFIER_NAME);
+
+ return g.buildStringAttribute(EID_SECTOR_FOR_IDENTIFIER_FRIENDLY_NAME,
+ EID_SECTOR_FOR_IDENTIFIER_NAME, bpktype);
+ }
+
+ public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) {
+ return g.buildEmptyAttribute(EID_SECTOR_FOR_IDENTIFIER_FRIENDLY_NAME,
+ EID_SECTOR_FOR_IDENTIFIER_NAME);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSourcePIN.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSourcePIN.java
new file mode 100644
index 00000000..52654f86
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSourcePIN.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.builder.attributes;
+
+import org.apache.commons.lang3.StringUtils;
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IPVPAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+import at.gv.egiz.eaaf.core.exceptions.AttributePolicyException;
+import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException;
+
+public class EIDSourcePIN implements IPVPAttributeBuilder {
+
+ public String getName() {
+ return EID_SOURCE_PIN_NAME;
+ }
+
+ public <ATT> ATT build(ISPConfiguration oaParam, IAuthData authData,
+ IAttributeGenerator<ATT> g) throws AttributeBuilderException {
+
+ if (authData.isBaseIDTransferRestrication())
+ throw new AttributePolicyException(EID_SOURCE_PIN_NAME);
+
+ else {
+ if (StringUtils.isNoneEmpty(authData.getIdentificationValue()))
+ throw new UnavailableAttributeException(EID_SOURCE_PIN_NAME);
+
+ return g.buildStringAttribute(EID_SOURCE_PIN_FRIENDLY_NAME, EID_SOURCE_PIN_NAME, authData.getIdentificationValue());
+ }
+ }
+
+ public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) {
+ return g.buildEmptyAttribute(EID_SOURCE_PIN_FRIENDLY_NAME, EID_SOURCE_PIN_NAME);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSourcePINType.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSourcePINType.java
new file mode 100644
index 00000000..ef2d8e82
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDSourcePINType.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.builder.attributes;
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IPVPAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException;
+
+public class EIDSourcePINType implements IPVPAttributeBuilder {
+
+ public String getName() {
+ return EID_SOURCE_PIN_TYPE_NAME;
+ }
+
+ public <ATT> ATT build(ISPConfiguration oaParam, IAuthData authData,
+ IAttributeGenerator<ATT> g) throws AttributeBuilderException {
+
+ if (authData.isBaseIDTransferRestrication())
+ throw new UnavailableAttributeException(EID_SOURCE_PIN_TYPE_NAME);
+
+ else {
+ return g.buildStringAttribute(EID_SOURCE_PIN_TYPE_FRIENDLY_NAME, EID_SOURCE_PIN_TYPE_NAME, authData.getIdentificationType());
+ }
+ }
+
+ public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) {
+ return g.buildEmptyAttribute(EID_SOURCE_PIN_TYPE_FRIENDLY_NAME, EID_SOURCE_PIN_TYPE_NAME);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDeIDASQAALevelAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDeIDASQAALevelAttributeBuilder.java
new file mode 100644
index 00000000..213faeb8
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EIDeIDASQAALevelAttributeBuilder.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.builder.attributes;
+
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IPVPAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+
+public class EIDeIDASQAALevelAttributeBuilder implements IPVPAttributeBuilder {
+
+ public String getName() {
+ return EID_CITIZEN_EIDAS_QAA_LEVEL_NAME;
+ }
+
+ public <ATT> ATT build(ISPConfiguration oaParam, IAuthData authData,
+ IAttributeGenerator<ATT> g) throws AttributeBuilderException {
+
+ return g.buildStringAttribute(EID_CITIZEN_EIDAS_QAA_LEVEL_FRIENDLY_NAME,
+ EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, authData.getEIDASQAALevel());
+ }
+
+
+ public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) {
+ return g.buildEmptyAttribute(EID_CITIZEN_EIDAS_QAA_LEVEL_FRIENDLY_NAME,
+ EID_CITIZEN_EIDAS_QAA_LEVEL_NAME);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/GivenNameAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/GivenNameAttributeBuilder.java
new file mode 100644
index 00000000..083adb36
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/GivenNameAttributeBuilder.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.builder.attributes;
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IPVPAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+
+public class GivenNameAttributeBuilder implements IPVPAttributeBuilder {
+
+ public String getName() {
+ return GIVEN_NAME_NAME;
+ }
+
+ public <ATT> ATT build(ISPConfiguration oaParam, IAuthData authData,
+ IAttributeGenerator<ATT> g) throws AttributeBuilderException {
+ return g.buildStringAttribute(GIVEN_NAME_FRIENDLY_NAME, GIVEN_NAME_NAME, authData.getGivenName());
+ }
+
+ public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) {
+ return g.buildEmptyAttribute(GIVEN_NAME_FRIENDLY_NAME, GIVEN_NAME_NAME);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/PVPVersionAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/PVPVersionAttributeBuilder.java
new file mode 100644
index 00000000..006f9854
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/PVPVersionAttributeBuilder.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.builder.attributes;
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IPVPAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+
+public class PVPVersionAttributeBuilder implements IPVPAttributeBuilder {
+
+ public String getName() {
+ return PVP_VERSION_NAME;
+ }
+
+ public <ATT> ATT build(ISPConfiguration oaParam, IAuthData authData,
+ IAttributeGenerator<ATT> g) throws AttributeBuilderException {
+ return g.buildStringAttribute(PVP_VERSION_FRIENDLY_NAME, PVP_VERSION_NAME, PVP_VERSION_2_1);
+ }
+
+ public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) {
+ return g.buildEmptyAttribute(PVP_VERSION_FRIENDLY_NAME, PVP_VERSION_NAME);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/PrincipalNameAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/PrincipalNameAttributeBuilder.java
new file mode 100644
index 00000000..8828a022
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/PrincipalNameAttributeBuilder.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.builder.attributes;
+
+import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IPVPAttributeBuilder;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException;
+
+public class PrincipalNameAttributeBuilder implements IPVPAttributeBuilder {
+
+ public String getName() {
+ return PRINCIPAL_NAME_NAME;
+ }
+
+ public <ATT> ATT build(ISPConfiguration oaParam, IAuthData authData,
+ IAttributeGenerator<ATT> g) throws AttributeBuilderException {
+ return g.buildStringAttribute(PRINCIPAL_NAME_FRIENDLY_NAME, PRINCIPAL_NAME_NAME, authData.getFamilyName());
+ }
+
+ public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) {
+ return g.buildEmptyAttribute(PRINCIPAL_NAME_FRIENDLY_NAME, PRINCIPAL_NAME_NAME);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/AbstractConfigurationImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/AbstractConfigurationImpl.java
new file mode 100644
index 00000000..2b868b16
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/AbstractConfigurationImpl.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.conf;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException;
+import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils;
+
+public abstract class AbstractConfigurationImpl implements IConfiguration {
+ private static final Logger log = LoggerFactory.getLogger(AbstractConfigurationImpl.class);
+
+ private static final String URI_SCHEME_CLASSPATH = "classpath";
+ private static final String URI_SCHEME_FILESYSTEM = "file";
+
+ private final URI internalConfigPath;
+ private final URI configRootDirectory;
+ private final Properties properties;
+
+ public AbstractConfigurationImpl(final String configPath) throws EAAFConfigurationException {
+ InputStream is = null;
+ try {
+ log.debug("Starting EAAFCore initialization process .... ");
+
+ if (StringUtils.isEmpty(configPath)) {
+ log.debug("Primary configuration is empty. Search for backup configuration .... ");
+ internalConfigPath = new URI(getBackupConfigPath());
+
+ } else
+ internalConfigPath = new URI(configPath);
+
+ log.info("Load EAAFCore configuration from " + internalConfigPath);
+
+
+ //extract configuration root directory
+ //TODO: check if it works with classpath
+ File propertiesFile = new File(internalConfigPath);
+ String configDir = propertiesFile.getParent();
+ configRootDirectory = new File(configDir).toURI();
+ log.debug("Set EAAFCore configuration root directory to " + configRootDirectory.toString());
+
+
+ //get input stream from configuration path
+ if (internalConfigPath.getScheme().equals(URI_SCHEME_FILESYSTEM)) {
+ log.trace("Load config from filesystem");
+ is = new FileInputStream(propertiesFile);
+
+ } else if (internalConfigPath.getScheme().equals(URI_SCHEME_CLASSPATH)) {
+ log.trace("Load config from classpath");
+ is = this.getClass().getResourceAsStream(internalConfigPath.toString());
+
+ } else {
+ log.error("Can not load EAAFCore configuration. Unsupported prefix! (Only 'file:' and 'classpath:') ");
+ throw new EAAFConfigurationException("Can not load EAAFCore configuration. Unsupported prefix");
+
+ }
+
+ if (is == null) {
+ log.error("Can NOT load EAAFCore configuration from file " + internalConfigPath.toString());
+ throw new EAAFConfigurationException("Can NOT load EAAFCore configuration from file " + internalConfigPath.toString());
+
+ }
+
+
+ //load EAAF core configuration into properties object
+ properties = new Properties();
+ properties.load(is);
+
+ log.info("EAAFCore configuration loaded");
+
+
+ } catch (URISyntaxException | IOException e) {
+ log.error("Can not parse configuration path " + configPath + " or " + getBackupConfigPath());
+ throw new EAAFConfigurationException("Can not parse configuration path", e);
+
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+
+ } catch (IOException e) {
+ log.warn("Can not close inputstream from configuration loader!");
+
+ }
+ }
+ }
+
+ }
+
+ @Override
+ public String getBasicConfiguration(String key) {
+ if (StringUtils.isNotEmpty(key)) {
+ String value = properties.getProperty(addPrefixToKey(key));
+ if (value != null)
+ return value.trim();
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getBasicConfiguration(String key, String defaultValue) {
+ if (StringUtils.isNotEmpty(key)) {
+ String value = properties.getProperty(addPrefixToKey(key), defaultValue);
+ if (value != null)
+ return value.trim();
+ }
+
+ return defaultValue;
+ }
+
+ @Override
+ public Map<String, String> getBasicMOAIDConfigurationWithPrefix(String prefix) {
+ return KeyValueUtils.getSubSetWithPrefix(KeyValueUtils.convertPropertiesToMap(properties), addPrefixToKey(prefix));
+
+ }
+
+ @Override
+ public boolean getBasicMOAIDConfigurationBoolean(String key, boolean defaultValue) {
+ String value = getBasicConfiguration(key);
+ if (StringUtils.isNotEmpty(value))
+ return Boolean.valueOf(value.trim());
+
+ return defaultValue;
+
+ }
+
+ @Override
+ public Properties getFullConfigurationProperties() {
+ return properties;
+
+ }
+
+ @Override
+ public URI getConfigurationRootDirectory() {
+ return configRootDirectory;
+
+ }
+
+ @Override
+ public URI getConfigurationFilePath() {
+ return internalConfigPath;
+
+ }
+
+ /**
+ * Get the path to backup configuration
+ *
+ * @return A filepath file: or a classpath classpath:
+ */
+ abstract protected String getBackupConfigPath();
+
+ /**
+ * Get a specific configuration-key prefix for this software implementation
+ *
+ * @return
+ */
+ abstract public String getApplicationSpecificKeyPrefix();
+
+
+ private String addPrefixToKey(String key) {
+ if (StringUtils.isNotEmpty(getApplicationSpecificKeyPrefix())) {
+ if (getApplicationSpecificKeyPrefix().endsWith(KeyValueUtils.KEY_DELIMITER))
+ return getApplicationSpecificKeyPrefix() + key;
+ else
+ return getApplicationSpecificKeyPrefix() + KeyValueUtils.KEY_DELIMITER + key;
+
+ }
+
+ return key;
+
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/SPConfigurationImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/SPConfigurationImpl.java
new file mode 100644
index 00000000..e402983d
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/conf/SPConfigurationImpl.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.conf;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConfigConstants;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils;
+
+public class SPConfigurationImpl implements ISPConfiguration {
+ private static final long serialVersionUID = 688541755446463453L;
+
+ private static final Logger log = LoggerFactory.getLogger(SPConfigurationImpl.class);
+
+ private final Map<String, String> spConfiguration;
+ private final List<String> targetAreasWithNoInteralBaseIdRestriction;
+ private final List<String> targetAreasWithNoBaseIdTransmissionRestriction;
+
+
+ public SPConfigurationImpl(final Map<String, String> spConfig, IConfiguration authConfig) {
+ this.spConfiguration = spConfig;
+
+ //set oa specific restrictions
+ targetAreasWithNoInteralBaseIdRestriction = Collections.unmodifiableList(
+ KeyValueUtils.getListOfCSVValues(
+ authConfig.getBasicConfiguration(
+ CONFIG_KEY_RESTRICTIONS_BASEID_INTERNAL,
+ EAAFConstants.URN_PREFIX_CDID)));
+
+ targetAreasWithNoBaseIdTransmissionRestriction = Collections.unmodifiableList(
+ KeyValueUtils.getListOfCSVValues(
+ authConfig.getBasicConfiguration(
+ CONFIG_KEY_RESTRICTIONS_BASEID_TRANSMISSION,
+ EAAFConstants.URN_PREFIX_CDID)));
+
+ if (log.isTraceEnabled()) {
+ log.trace("Internal policy for OA: " + getUniqueIdentifier());
+ for (String el : targetAreasWithNoInteralBaseIdRestriction)
+ log.trace(" Allow baseID processing for prefix " + el);
+ for (String el : targetAreasWithNoBaseIdTransmissionRestriction)
+ log.trace(" Allow baseID transfer for prefix " + el);
+
+ }
+ }
+
+
+ @Override
+ public final Map<String, String> getFullConfiguration() {
+ return this.spConfiguration;
+
+ }
+
+ @Override
+ public final String getConfigurationValue(String key) {
+ if (key == null)
+ return null;
+ else
+ return this.spConfiguration.get(key);
+
+ }
+
+ @Override
+ public final String getConfigurationValue(String key, String defaultValue) {
+ String value = getConfigurationValue(key);
+ if (value == null)
+ return defaultValue;
+ else
+ return value;
+ }
+
+
+ @Override
+ public final Boolean isConfigurationValue(String key) {
+ String value = getConfigurationValue(key);
+ if (value != null) {
+ return Boolean.parseBoolean(value);
+
+ }
+
+ return null;
+ }
+
+
+ @Override
+ public final boolean isConfigurationValue(String key, boolean defaultValue) {
+ String value = getConfigurationValue(key);
+ if (value != null) {
+ return Boolean.parseBoolean(value);
+
+ }
+
+ return defaultValue;
+ }
+
+ @Override
+ public final boolean containsConfigurationKey(String key) {
+ if (key == null)
+ return false;
+ else
+ return this.spConfiguration.containsKey(key);
+
+ }
+
+ @Override
+ public String getUniqueIdentifier() {
+ return getConfigurationValue(EAAFConfigConstants.SERVICE_UNIQUEIDENTIFIER);
+
+ }
+
+ @Override
+ public boolean hasBaseIdInternalProcessingRestriction() {
+ return false;
+
+ }
+
+ @Override
+ public boolean hasBaseIdTransferRestriction() {
+ return true;
+
+ }
+
+
+ @Override
+ public final List<String> getTargetsWithNoBaseIdInternalProcessingRestriction() {
+ return this.targetAreasWithNoInteralBaseIdRestriction;
+ }
+
+
+ @Override
+ public final List<String> getTargetsWithNoBaseIdTransferRestriction() {
+ return this.targetAreasWithNoBaseIdTransmissionRestriction;
+ }
+
+
+ @Override
+ public String getMinimumLevelOfAssurence() {
+ log.warn("Method not implemented: " + SPConfigurationImpl.class.getName() + " 'getMinimumLevelOfAssurence()'");
+ return null;
+ }
+
+
+ @Override
+ public String getAreaSpecificTargetIdentifier() {
+ log.warn("Method not implemented: " + SPConfigurationImpl.class.getName() + " 'getAreaSpecificTargetIdentifier()'");
+ return null;
+ }
+
+
+ @Override
+ public String getFriendlyName() {
+ log.warn("Method not implemented: " + SPConfigurationImpl.class.getName() + " 'getFriendlyName()'");
+ return null;
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractAuthProtocolModulController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractAuthProtocolModulController.java
new file mode 100644
index 00000000..d72ee404
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractAuthProtocolModulController.java
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.controller;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import at.gv.egiz.components.eventlog.api.EventConstants;
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.IStatusMessager;
+import at.gv.egiz.eaaf.core.api.idp.IAction;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IAuthenticationDataBuilder;
+import at.gv.egiz.eaaf.core.api.idp.IModulInfo;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.auth.IAuthenticationManager;
+import at.gv.egiz.eaaf.core.api.idp.auth.ISSOManager;
+import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface;
+import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFSSOException;
+
+/**
+ * @author tlenz
+ *
+ */
+
+public abstract class AbstractAuthProtocolModulController extends AbstractController {
+ private static final Logger log = LoggerFactory.getLogger(AbstractAuthProtocolModulController.class);
+
+ public static final String ENDPOINT_FINALIZEPROTOCOL = "finalizeAuthProtocol";
+ public static final String ENDPOINT_ERRORHANDLING = "errorHandling";
+
+
+ @Autowired(required=true) private IAuthenticationManager authmanager;
+ @Autowired(required=true) private IAuthenticationDataBuilder authDataBuilder;
+ @Autowired(required=false) private ISSOManager ssoManager;
+
+ /**
+ * Initialize an authentication process for this protocol request
+ *
+ * @param httpReq HttpServletRequest
+ * @param httpResp HttpServletResponse
+ * @param protocolRequest Authentication request which is actually in process
+ * @throws IOException
+ */
+ protected void performAuthentication(HttpServletRequest req, HttpServletResponse resp,
+ IRequest pendingReq) throws IOException {
+ try {
+ if (pendingReq.isNeedAuthentication()) {
+ //request needs authentication --> start authentication process ...
+
+ //load Parameters from OnlineApplicationConfiguration
+ ISPConfiguration oaParam = pendingReq.getServiceProviderConfiguration();
+
+ if (oaParam == null)
+ throw new EAAFAuthenticationException(
+ IStatusMessager.CODES_INTERNAL_ERROR_AUTH_NOSPCONFIG,
+ new Object[] { pendingReq.getSPEntityId() },
+ "No Service Provider configuration found.");
+
+ if (authmanager.doAuthentication(req, resp, pendingReq)) {
+ //pending request is already authenticated --> protocol-specific postProcessing can start directly
+ finalizeAuthenticationProcess(req, resp, pendingReq);
+
+ //transaction is finished, log transaction finished event
+ revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, pendingReq.getUniqueTransactionIdentifier());
+
+ }
+
+ } else {
+ executeProtocolSpecificAction(req, resp, pendingReq, null);
+
+ }
+
+ } catch (Exception e) {
+ buildProtocolSpecificErrorResponse(e, req, resp, pendingReq);
+ authmanager.performOnlyIDPLogOut(req, resp, pendingReq);
+
+ }
+ }
+
+
+ /**
+ * Finalize the requested protocol operation
+ *
+ * @param httpReq HttpServletRequest
+ * @param httpResp HttpServletResponse
+ * @param protocolRequest Authentication request which is actually in process
+ * @param moaSession MOASession object, which is used to generate the protocol specific authentication information
+ * @throws Exception
+ */
+ protected void finalizeAuthenticationProcess(HttpServletRequest req, HttpServletResponse resp,
+ IRequest pendingReq) throws Exception {
+
+ String newSSOSessionId = null;
+
+ //if Single Sign-On functionality is enabled for this request
+ if (pendingReq.needSingleSignOnFunctionality()) {
+ if (ssoManager != null)
+ newSSOSessionId = ssoManager.createNewSSOSessionCookie(req, resp, pendingReq);
+ else
+ log.warn("SSO is requested but there is not SSO Session-Manager available");
+
+ }
+
+ //build authenticationdata from session information and OA configuration
+ IAuthData authData = authDataBuilder.buildAuthenticationData(pendingReq);
+
+ //execute the protocol-specific action
+ SLOInformationInterface sloInformation = executeProtocolSpecificAction(req, resp, pendingReq, authData);
+
+ //Store OA specific SSO session information if an SSO cookie is set
+ if (StringUtils.isNotEmpty(newSSOSessionId)) {
+ try {
+ //create new SSO session, if actually no SSO session exists
+ if (StringUtils.isEmpty(pendingReq.getSSOSessionIdentifier())) {
+ ssoManager.createNewSSOSession(pendingReq, newSSOSessionId, sloInformation);
+
+ //MOA SSO-session already exists only update is required
+ } else {
+ ssoManager.updateSSOSession(pendingReq, newSSOSessionId, sloInformation);
+
+
+ }
+
+ } catch (EAAFSSOException e) {
+ log.warn("SSO Session information can not be stored -> SSO is not enabled!");
+ authmanager.performOnlyIDPLogOut(req, resp, pendingReq);
+
+ }
+
+ } else {
+ //remove MOASession from database
+ authmanager.performOnlyIDPLogOut(req, resp, pendingReq);
+
+ }
+
+ //Advanced statistic logging
+ statisticLogger.logSuccessOperation(pendingReq, authData, StringUtils.isNotEmpty(newSSOSessionId));
+
+ }
+
+ /**
+ * Executes the requested protocol action
+ *
+ * @param httpReq HttpServletRequest
+ * @param httpResp HttpServletResponse
+ * @param protocolRequest Authentication request which is actually in process
+ * @param authData Service-provider specific authentication data
+ *
+ * @return Return Single LogOut information or null if protocol supports no SSO
+ *
+ * @throws Exception
+ */
+ private SLOInformationInterface executeProtocolSpecificAction(HttpServletRequest httpReq, HttpServletResponse httpResp,
+ IRequest pendingReq, IAuthData authData) throws Exception {
+ try {
+ // request needs no authentication --> start request processing
+ Class<?> clazz = Class.forName(pendingReq.requestedAction());
+ if (clazz == null ||
+ !IAction.class.isAssignableFrom(clazz)) {
+ log.error("Requested protocol-action processing Class is NULL or does not implement the IAction interface.");
+ throw new Exception("Requested protocol-action processing Class is NULL or does not implement the IAction interface.");
+
+ }
+
+ IAction protocolAction = (IAction) applicationContext.getBean(clazz);
+ return protocolAction.processRequest(pendingReq, httpReq, httpResp, authData);
+
+ } catch (ClassNotFoundException e) {
+ log.error("Requested Auth. protocol processing Class is NULL or does not implement the IAction interface.");
+ throw new Exception("Requested Auth. protocol processing Class is NULL or does not implement the IAction interface.");
+ }
+
+ }
+
+ protected void buildProtocolSpecificErrorResponse(Throwable throwable, HttpServletRequest req,
+ HttpServletResponse resp, IRequest protocolRequest) throws IOException {
+ try {
+
+ Class<?> clazz = Class.forName(protocolRequest.requestedModule());
+
+ if (clazz == null ||
+ !IModulInfo.class.isAssignableFrom(clazz)) {
+ log.error("Requested protocol module Class is NULL or does not implement the IModulInfo interface.");
+ throw new Exception("Requested protocol module Class is NULL or does not implement the IModulInfo interface.");
+
+ }
+
+ IModulInfo handlingModule = (IModulInfo) applicationContext.getBean(clazz);
+
+ if (handlingModule.generateErrorMessage(
+ throwable, req, resp, protocolRequest)) {
+
+ //log Error to technical log
+ logExceptionToTechnicalLog(throwable);
+
+ //log Error Message
+ statisticLogger.logErrorOperation(throwable, protocolRequest);
+
+ //write revision log entries
+ revisionsLogger.logEvent(protocolRequest, EventConstants.TRANSACTION_ERROR, protocolRequest.getUniqueTransactionIdentifier());
+
+ return;
+
+ } else {
+ handleErrorNoRedirect(throwable, req, resp, true);
+
+ }
+
+ } catch (Throwable e) {
+ handleErrorNoRedirect(throwable, req, resp, true);
+
+ }
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java
new file mode 100644
index 00000000..980d77ba
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java
@@ -0,0 +1,354 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.controller;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.naming.ConfigurationException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.text.StringEscapeUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+import at.gv.egiz.components.eventlog.api.EventConstants;
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.IRequestStorage;
+import at.gv.egiz.eaaf.core.api.IStatusMessager;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.data.ExceptionContainer;
+import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfiguration;
+import at.gv.egiz.eaaf.core.api.gui.IGUIBuilderConfigurationFactory;
+import at.gv.egiz.eaaf.core.api.gui.IGUIFormBuilder;
+import at.gv.egiz.eaaf.core.api.gui.ModifyableGuiBuilderConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger;
+import at.gv.egiz.eaaf.core.api.logging.IStatisticLogger;
+import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage;
+import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.GUIBuildException;
+import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException;
+import at.gv.egiz.eaaf.core.exceptions.ProcessExecutionException;
+import at.gv.egiz.eaaf.core.exceptions.ProtocolNotActiveException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.utils.HTTPUtils;
+import at.gv.egiz.eaaf.core.impl.utils.Random;
+import at.gv.egiz.eaaf.core.impl.utils.ServletUtils;
+
+
+/**
+ * @author tlenz
+ *
+ */
+public abstract class AbstractController {
+
+ private static final Logger log = LoggerFactory.getLogger(AbstractController.class);
+
+ @Autowired(required=true) protected ApplicationContext applicationContext;
+ @Autowired(required=true) protected IConfiguration authConfig;
+ @Autowired(required=true) protected ITransactionStorage transactionStorage;
+ @Autowired(required=true) protected IRequestStorage requestStorage;
+ @Autowired(required=true) protected IGUIFormBuilder guiBuilder;
+ @Autowired(required=true) protected IGUIBuilderConfigurationFactory guiConfigFactory;
+ @Autowired(required=true) protected IStatusMessager statusMessager;
+
+ @Autowired protected IStatisticLogger statisticLogger;
+ @Autowired protected IRevisionLogger revisionsLogger;
+
+
+
+
+
+ @ExceptionHandler({EAAFException.class})
+ public void MOAIDExceptionHandler(HttpServletRequest req, HttpServletResponse resp, Exception e) throws IOException {
+ log.error(e.getMessage() , e);
+ internalMOAIDExceptionHandler(req, resp, e, true);
+
+ }
+
+ @ExceptionHandler({Exception.class})
+ public void GenericExceptionHandler(HttpServletResponse resp, Exception exception) throws IOException {
+ log.error("Internel Server Error." , exception);
+ resp.setContentType(EAAFConstants.CONTENTTYPE_HTML_UTF8);
+ resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error!" +
+ "(Errorcode=9199"
+ +" | Description="
+ + StringEscapeUtils.escapeHtml4(StringEscapeUtils.escapeEcmaScript(exception.getMessage()))
+ + ")");
+ return;
+
+ }
+
+ @ExceptionHandler({IOException.class})
+ public void IOExceptionHandler(HttpServletResponse resp, Throwable exception) {
+ log.error("Internel Server Error." , exception);
+ resp.setContentType(EAAFConstants.CONTENTTYPE_HTML_UTF8);
+ resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ return;
+
+ }
+
+ protected void handleError(String errorMessage, Throwable exceptionThrown,
+ HttpServletRequest req, HttpServletResponse resp, IRequest pendingReq) throws IOException {
+
+ String pendingRequestID = null;
+ if (pendingReq != null)
+ pendingRequestID = pendingReq.getPendingRequestId();
+
+ Throwable loggedException = null;
+ Throwable extractedException = extractOriginalExceptionFromProcessException(exceptionThrown);
+
+ //extract pendingRequestID and originalException if it was a TaskExecutionException
+ if (extractedException instanceof TaskExecutionException) {
+ //set original exception
+ loggedException = ((TaskExecutionException) extractedException).getOriginalException();
+
+ //use TaskExecutionException directly, if no Original Exeception is included
+ if (loggedException == null)
+ loggedException = exceptionThrown;
+
+ //set pending-request ID if it is set
+ String reqID = ((TaskExecutionException) extractedException).getPendingRequestID();
+ if (StringUtils.isNotEmpty(reqID))
+ pendingRequestID = reqID;
+
+ } else
+ loggedException = exceptionThrown;
+
+ try {
+ //switch to protocol-finalize method to generate a protocol-specific error message
+
+ //log error directly in debug mode
+ if (log.isDebugEnabled())
+ log.warn(loggedException.getMessage(), loggedException);
+
+
+ //put exception into transaction store for redirect
+ String key = Random.nextLongRandom();
+ if (pendingReq != null) {
+ revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR);
+ transactionStorage.put(key,
+ new ExceptionContainer(pendingReq, loggedException), -1);
+
+ } else {
+ transactionStorage.put(key,
+ new ExceptionContainer(null, loggedException), -1);
+
+ }
+
+ //build up redirect URL
+ String redirectURL = null;
+ redirectURL = ServletUtils.getBaseUrl(req);
+ redirectURL += "/"+AbstractAuthProtocolModulController.ENDPOINT_ERRORHANDLING
+ + "?" + EAAFConstants.PARAM_HTTP_ERROR_CODE + "=" + key;
+
+// //only add pending-request Id if it exists
+// if (StringUtils.isNotEmpty(pendingRequestID))
+// redirectURL += "&" + EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID + "=" + pendingRequestID;
+
+ resp.setContentType("text/html");
+ resp.setStatus(302);
+
+ resp.addHeader("Location", redirectURL);
+ log.debug("REDIRECT TO: " + redirectURL);
+
+ return;
+
+ } catch (Exception e) {
+ log.warn("Default error-handling FAILED. Exception can not be stored ....", e);
+ log.info("Switch to generic generic backup error-handling ... ");
+ handleErrorNoRedirect(loggedException, req, resp, true);
+
+ }
+
+ }
+
+ /**
+ * Handles all exceptions with no pending request.
+ * Therefore, the error is written to the users browser
+ *
+ * @param throwable
+ * @param req
+ * @param resp
+ * @throws IOException
+ */
+ protected void handleErrorNoRedirect(Throwable throwable, HttpServletRequest req,
+ HttpServletResponse resp, boolean writeExceptionToStatisticLog) throws IOException {
+
+ //log Exception into statistic database
+ if (writeExceptionToStatisticLog)
+ statisticLogger.logErrorOperation(throwable);
+
+ //write errror to console
+ logExceptionToTechnicalLog(throwable);
+
+ //return error to Web browser
+ if (throwable instanceof EAAFException || throwable instanceof ProcessExecutionException)
+ internalMOAIDExceptionHandler(req, resp, (Exception)throwable, false);
+
+ else {
+ //write generic message for general exceptions
+ String msg = statusMessager.getMessage(IStatusMessager.CODES_INTERNAL_ERROR_GENERIC, null);
+ writeHTMLErrorResponse(req, resp, msg, "9199", (Exception) throwable);
+
+ }
+
+ }
+
+ /**
+ * Write a Exception to the MOA-ID-Auth internal technical log
+ *
+ * @param loggedException Exception to log
+ */
+ protected void logExceptionToTechnicalLog(Throwable loggedException) {
+ if (!( loggedException instanceof EAAFException
+ || loggedException instanceof ProcessExecutionException )) {
+ log.error("Receive an internal error: Message=" + loggedException.getMessage(), loggedException);
+
+ } else {
+ if (log.isDebugEnabled() || log.isTraceEnabled()) {
+ log.warn(loggedException.getMessage(), loggedException);
+
+ } else {
+ log.warn(loggedException.getMessage());
+
+ }
+ }
+ }
+
+ private void writeBadRequestErrorResponse(HttpServletRequest req, HttpServletResponse resp, EAAFException e) throws IOException {
+ String code = statusMessager.mapInternalErrorToExternalError(((InvalidProtocolRequestException)e).getErrorId());
+ String descr = StringEscapeUtils.escapeHtml4(StringEscapeUtils.escapeEcmaScript(e.getMessage()));
+ resp.setContentType(EAAFConstants.CONTENTTYPE_HTML_UTF8);
+ resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Protocol validation FAILED!" +
+ "(Errorcode=" + code +
+ " | Description=" + descr + ")");
+
+ }
+
+ private void writeHTMLErrorResponse(HttpServletRequest req, HttpServletResponse httpResp, String msg, String errorCode, Exception error) throws IOException {
+
+ try {
+ IGUIBuilderConfiguration config
+ = guiConfigFactory.getDefaultErrorGUI(HTTPUtils.extractAuthURLFromRequest(req));
+
+// HTTPUtils.extractAuthURLFromRequest(req),
+// DefaultGUIFormBuilderConfiguration.VIEW_ERRORMESSAGE,
+// null);
+
+ //add errorcode and errormessage
+ if (config instanceof ModifyableGuiBuilderConfiguration) {
+ ((ModifyableGuiBuilderConfiguration)config).putCustomParameter("errorMsg", msg);
+ ((ModifyableGuiBuilderConfiguration)config).putCustomParameter("errorCode", errorCode);
+
+ //add stacktrace if debug is enabled
+ if (log.isTraceEnabled()) {
+ ((ModifyableGuiBuilderConfiguration)config).putCustomParameter("stacktrace", getStacktraceFromException(error));
+
+ }
+
+ } else
+ log.info("Can not ADD error message, because 'GUIBuilderConfiguration' is not modifieable ");
+
+
+
+ guiBuilder.build(httpResp, config, "Error-Message");
+
+ } catch (GUIBuildException e) {
+ log.warn("Can not build error-message GUI.", e);
+ GenericExceptionHandler(httpResp, e);
+
+ }
+
+ }
+
+ private void writeHTMLErrorResponse(HttpServletRequest req, HttpServletResponse httpResp, Exception error) throws IOException {
+ writeHTMLErrorResponse(req, httpResp,
+ error.getMessage(),
+ statusMessager.getResponseErrorCode(error),
+ error);
+ }
+
+
+ private String getStacktraceFromException(Exception ex) {
+ StringWriter errors = new StringWriter();
+ ex.printStackTrace(new PrintWriter(errors));
+ return errors.toString();
+
+ }
+
+ /**
+ * Extracts a TaskExecutionException of a ProcessExecutionExeception Stacktrace.
+ *
+ * @param exception
+ * @return Return the latest TaskExecutionExecption if exists, otherwise the latest ProcessExecutionException
+ */
+ private Throwable extractOriginalExceptionFromProcessException(Throwable exception) {
+ Throwable exholder = exception;
+ TaskExecutionException taskExc = null;
+
+ while(exholder != null
+ && exholder instanceof ProcessExecutionException) {
+ ProcessExecutionException procExc = (ProcessExecutionException) exholder;
+ if (procExc.getCause() != null &&
+ procExc.getCause() instanceof TaskExecutionException) {
+ taskExc = (TaskExecutionException) procExc.getCause();
+ exholder = taskExc.getOriginalException();
+
+ } else
+ break;
+
+ }
+
+ if (taskExc == null)
+ return exholder;
+
+ else
+ return taskExc;
+ }
+
+ private void internalMOAIDExceptionHandler(HttpServletRequest req, HttpServletResponse resp, Exception e, boolean writeExceptionToStatisicLog) throws IOException {
+ if (e instanceof ProtocolNotActiveException) {
+ resp.getWriter().write(e.getMessage());
+ resp.setContentType(EAAFConstants.CONTENTTYPE_HTML_UTF8);
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN,
+ StringEscapeUtils.escapeHtml4(StringEscapeUtils.escapeEcmaScript(e.getMessage())));
+
+ } else if (e instanceof AuthnRequestValidatorException) {
+ AuthnRequestValidatorException ex = (AuthnRequestValidatorException)e;
+ //log Error Message
+ if (writeExceptionToStatisicLog)
+ statisticLogger.logErrorOperation(ex, ex.getErrorRequest());
+
+ //write error message
+ writeBadRequestErrorResponse(req, resp, (EAAFException) e);
+
+ } else if (e instanceof InvalidProtocolRequestException) {
+ //send error response
+ writeBadRequestErrorResponse(req, resp, (EAAFException) e);
+
+ } else if (e instanceof ConfigurationException) {
+ //send HTML formated error message
+ writeHTMLErrorResponse(req, resp, (EAAFException) e);
+
+ } else if (e instanceof EAAFException) {
+ //send HTML formated error message
+ writeHTMLErrorResponse(req, resp, e);
+
+ } else if (e instanceof ProcessExecutionException) {
+ //send HTML formated error message
+ writeHTMLErrorResponse(req, resp, e);
+
+ }
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java
new file mode 100644
index 00000000..a4a86ca2
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.controller;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.text.StringEscapeUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.IStatusMessager;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFIllegalStateException;
+import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils;
+
+/**
+ * Servlet that resumes a suspended process (in case of asynchronous tasks).
+ *
+ * @author tknall
+ *
+ */
+public abstract class AbstractProcessEngineSignalController extends AbstractController {
+ private static final Logger log = LoggerFactory.getLogger(AbstractProcessEngineSignalController.class);
+
+ @Autowired protected ProcessEngine processEngine;
+
+ protected void signalProcessManagement(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ String pendingRequestID = StringEscapeUtils.escapeHtml4(getPendingRequestId(req));
+ IRequest pendingReq = null;
+ try {
+ if (pendingRequestID == null) {
+ new EAAFException(
+ IStatusMessager.CODES_INTERNAL_ERROR_AUTH_NOPENDIGREQID,
+ null,
+ "NO PendingRequestId found"
+ );
+
+ }
+
+ pendingReq = requestStorage.getPendingRequest(pendingRequestID);
+ if (pendingReq == null) {
+ log.info("No PendingRequest with Id: " + pendingRequestID + " Maybe, a transaction timeout occure.");
+ throw new EAAFException(IStatusMessager.CODES_INTERNAL_ERROR_AUTH_TIMEOUT, new Object[]{pendingRequestID},
+ "No PendingRequest with Id: \" + pendingRequestID + \" Maybe, a transaction timeout occure.\"");
+
+ }
+
+ //change pending-request ID
+ requestStorage.changePendingRequestID(pendingReq);
+ pendingRequestID = pendingReq.getPendingRequestId();
+
+ // process instance is mandatory
+ if (pendingReq.getProcessInstanceId() == null) {
+ throw new EAAFIllegalStateException(new Object[]{"MOA session does not provide process instance id."},
+ "No execution environemnt found for this pending request");
+
+ }
+
+ // wake up next task
+ processEngine.signal(pendingReq);
+
+ } catch (Exception ex) {
+ handleError(null, ex, req, resp, pendingReq);
+
+ } finally {
+ //MOASessionDBUtils.closeSession();
+ TransactionIDUtils.removeAllLoggingVariables();
+
+ }
+
+
+ }
+
+ /**
+ * Retrieves the current pending-request id from the HttpServletRequest parameter
+ *
+ * <p/>
+ * Note that this class/method can be overwritten by modules providing their own strategy of retrieving the
+ * respective pending-request id.
+ *
+ * @param request
+ * The unterlying HttpServletRequest.
+ * @return The current pending-request id.
+ */
+ public String getPendingRequestId(HttpServletRequest request) {
+ return StringEscapeUtils.escapeHtml4(request.getParameter(EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID));
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java
new file mode 100644
index 00000000..3659ff4f
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.controller;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.text.StringEscapeUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import at.gv.egiz.components.eventlog.api.EventConstants;
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.IStatusMessager;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.data.ExceptionContainer;
+import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+
+/**
+ * @author tlenz
+ *
+ */
+@Controller
+public class ProtocolFinalizationController extends AbstractAuthProtocolModulController {
+ private static final Logger log = LoggerFactory.getLogger(ProtocolFinalizationController.class);
+
+ @RequestMapping(value = ENDPOINT_ERRORHANDLING, method = {RequestMethod.GET})
+ public void errorHandling(HttpServletRequest req, HttpServletResponse resp) throws EAAFException, IOException {
+ //receive an authentication error
+ String errorid = StringEscapeUtils.escapeHtml4(req.getParameter(EAAFConstants.PARAM_HTTP_ERROR_CODE));
+ if (errorid != null) {
+ IRequest pendingReq = null;
+ try {
+ //load stored exception from database
+ ExceptionContainer container = transactionStorage.get(errorid, ExceptionContainer.class);
+ if (container != null) {
+ //remove exception if it was found
+ transactionStorage.remove(errorid);
+
+ Throwable throwable = container.getExceptionThrown();
+ pendingReq = container.getPendingRequest();
+
+ if (pendingReq != null) {
+ //build protocol-specific error message if possible
+ buildProtocolSpecificErrorResponse(throwable, req, resp, pendingReq);
+
+ //remove active user-session
+ transactionStorage.remove(pendingReq.getPendingRequestId());
+
+ return;
+
+ } else {
+ handleErrorNoRedirect(throwable, req, resp, true);
+
+ }
+ } else {
+ handleErrorNoRedirect(
+ new EAAFException(
+ IStatusMessager.CODES_INTERNAL_ERROR_AUTH_NOPENDIGREQID,
+ null,
+ "NO Error with this Id found"
+ ), req, resp, false);
+
+ }
+
+ } catch (Throwable e) {
+ log.error(e.getMessage(), e);
+ handleErrorNoRedirect(e, req, resp, false);
+
+ } finally {
+ //remove pending-request
+ if (pendingReq != null) {
+ requestStorage.removePendingRequest(pendingReq.getPendingRequestId());
+ revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, pendingReq.getUniqueTransactionIdentifier());
+
+ }
+
+ }
+
+ } else {
+ log.debug("Request contains NO ErrorId");
+ handleErrorNoRedirect(
+ new EAAFException(
+ IStatusMessager.CODES_INTERNAL_ERROR_AUTH_NOPENDIGREQID,
+ null,
+ "Request containts NO error id."
+ ), req, resp, false);
+
+ }
+
+ }
+
+
+ @RequestMapping(value = ENDPOINT_FINALIZEPROTOCOL, method = {RequestMethod.GET})
+ public void finalizeAuthProtocol(HttpServletRequest req, HttpServletResponse resp) throws EAAFException, IOException {
+
+ //read pendingRequest from http request
+ Object idObject = StringEscapeUtils.escapeHtml4(req.getParameter(EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID));
+ IRequest pendingReq = null;
+ String pendingRequestID = null;
+ if (idObject != null && (idObject instanceof String)) {
+ pendingRequestID = (String) idObject;
+ pendingReq = requestStorage.getPendingRequest(pendingRequestID);
+
+ }
+
+ if (pendingReq == null) {
+ log.error("No PendingRequest with ID " + pendingRequestID + " found.!");
+ handleErrorNoRedirect(
+ new EAAFException(
+ IStatusMessager.CODES_INTERNAL_ERROR_AUTH_TIMEOUT,
+ new Object[]{pendingRequestID,
+ },
+ "No pendigReq with Id: " + pendingRequestID), req, resp, false);
+
+ } else {
+ try {
+ log.debug("Finalize PendingRequest with ID " + pendingRequestID);
+
+ //check if pending-request has 'abortedByUser' flag set
+ if (pendingReq.isAbortedByUser()) {
+ //send authentication aborted error to Service Provider
+ buildProtocolSpecificErrorResponse(
+ new EAAFAuthenticationException(
+ IStatusMessager.CODES_INTERNAL_ERROR_AUTH_USERSTOP,
+ new Object[] {},
+ "User stops authentication process"),
+ req, resp, pendingReq);
+
+ //do not remove the full active SSO-Session
+ // in case of only one Service-Provider authentication request is aborted
+ if ( !pendingReq.needSingleSignOnFunctionality()) {
+ transactionStorage.remove(pendingReq.getPendingRequestId());
+
+ }
+
+ //check if pending-request are authenticated
+ } else if (pendingReq.isAuthenticated()) {
+ finalizeAuthenticationProcess(req, resp, pendingReq);
+
+ } else {
+ //suspect state: pending-request is not aborted but also are not authenticated
+ log.error("PendingRequest is NOT authenticated --> Abort authentication process!");
+ handleErrorNoRedirect(
+ new EAAFException(
+ "auth.20",
+ null,
+ "PendingRequest is NOT authenticated --> Abort authentication process!"
+ ), req, resp, true);
+
+ }
+
+ } catch (Exception e) {
+ log.error("Finalize authentication protocol FAILED." , e);
+ buildProtocolSpecificErrorResponse(e, req, resp, pendingReq);
+
+ if (pendingReq != null)
+ transactionStorage.remove(pendingReq.getPendingRequestId());
+
+ }
+ }
+
+ //remove pending-request
+ if (pendingReq != null) {
+ requestStorage.removePendingRequest(pendingReq.getPendingRequestId());
+ revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, pendingReq.getUniqueTransactionIdentifier());
+
+ }
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/protocols/RequestImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/protocols/RequestImpl.java
new file mode 100644
index 00000000..6a7f4440
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/protocols/RequestImpl.java
@@ -0,0 +1,386 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.controller.protocols;
+
+import java.io.Serializable;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.naming.ConfigurationException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException;
+import at.gv.egiz.eaaf.core.impl.utils.HTTPUtils;
+import at.gv.egiz.eaaf.core.impl.utils.Random;
+import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils;
+
+public abstract class RequestImpl implements IRequest, Serializable{
+
+ private static final Logger log = LoggerFactory.getLogger(RequestImpl.class);
+
+ public static final String DATAID_REQUESTER_IP_ADDRESS = "reqestImpl_requesterIPAddr";
+
+ private static final long serialVersionUID = 1L;
+
+ private String module = null;
+ private String action = null;
+
+ private String pendingRequestId;
+ private String processInstanceId;
+ private String ssoSessionId;
+
+ private String uniqueTransactionIdentifer;
+ private String uniqueSessionIdentifer;
+
+ private String requestedServiceProviderIdentifer;
+ private String idpAuthURL = null;
+
+ private ISPConfiguration spConfiguration = null;
+
+ private boolean passiv = false;
+ private boolean force = false;
+ private boolean isAbortedByUser = false;
+
+ //every request needs authentication by default
+ private boolean needAuthentication = true;
+
+ //every request is not authenticated by default
+ private boolean isAuthenticated = false;
+
+ //every request needs no SSO by default
+ private boolean needSSO = false;
+
+ private boolean needUserConsent = false;
+
+ private Map<String, Object> genericDataStorage = new HashMap<String, Object>();
+
+
+
+ /**
+ * @throws ConfigurationException
+ *
+ */
+ public final void initialize(HttpServletRequest req, IConfiguration authConfig) throws EAAFException {
+ //set pendingRequestId
+ pendingRequestId = Random.nextLongRandom();
+
+ //set unique transaction identifier for logging
+ uniqueTransactionIdentifer = Random.nextLongRandom();
+ TransactionIDUtils.setTransactionId(uniqueTransactionIdentifer);
+
+ //initialize session object
+ genericDataStorage.put(EAAFConstants.AUTH_DATA_CREATED, new Date());
+ //genericDataStorage.put(EAAFConstants.VALUE_SESSIONID, Random.nextLongRandom());
+
+ //check if End-Point is valid
+ String authURLString = HTTPUtils.extractAuthURLFromRequest(req);
+ URL authReqURL;
+ try {
+ authReqURL = new URL(authURLString);
+
+ } catch (MalformedURLException e) {
+ log.error("IDP AuthenticationServiceURL Prefix is not a valid URL." + authURLString, e);
+ throw new EAAFAuthenticationException("errorId", new Object[]{authURLString},
+ "IDP AuthenticationServiceURL Prefix is not a valid URL.", e);
+
+ }
+ this.idpAuthURL = authConfig.validateIDPURL(authReqURL);
+ if (this.idpAuthURL == null) {
+ log.warn("Extract AuthenticationServiceURL: " + authReqURL + " is NOT found in configuration.");
+ throw new EAAFAuthenticationException("errorId", new Object[]{authURLString},
+ "Extract AuthenticationServiceURL: " + authReqURL + " is NOT found in configuration.");
+
+ }
+
+ //set unique session identifier
+ String uniqueID = (String) req.getAttribute(EAAFConstants.UNIQUESESSIONIDENTIFIER);
+ if (StringUtils.isNotEmpty(uniqueID))
+ this.uniqueSessionIdentifer = uniqueID;
+
+ else {
+ log.debug("Create new sessionIdentifier for this pendingRequest ... ");
+ this.uniqueSessionIdentifer = Random.nextLongRandom();
+
+ }
+
+ //set requester's IP address
+ try {
+ setGenericDataToSession(DATAID_REQUESTER_IP_ADDRESS, req.getRemoteAddr());
+
+ } catch (EAAFStorageException e) {
+ log.info("Can NOT store remote IP address into 'pendingRequest'." , e);
+
+ }
+
+ }
+
+// /**
+// * This method map the protocol specific requested attributes to PVP 2.1 attributes.
+// *
+// * @return List of PVP 2.1 attribute names with maps all protocol specific attributes
+// */
+// public abstract Collection<String> getRequestedAttributes(MetadataProvider metadataProvider);
+
+ public final void setSPEntityId(String spIdentifier) {
+ this.requestedServiceProviderIdentifer = spIdentifier;
+ }
+
+ public final String getSPEntityId() {
+ return this.requestedServiceProviderIdentifer;
+ }
+
+ public final boolean isPassiv() {
+ return passiv;
+ }
+
+ public final boolean forceAuth() {
+ return force;
+ }
+
+ public final void setPassiv(boolean passiv) {
+ this.passiv = passiv;
+ }
+
+ public final void setForce(boolean force) {
+ this.force = force;
+ }
+
+ public final String requestedAction() {
+ return action;
+ }
+
+ public final void setAction(String action) {
+ this.action = action;
+ }
+
+ public final String requestedModule() {
+ return module;
+ }
+
+ public final void setModule(String module) {
+ this.module = module;
+ }
+
+ public final void setPendingRequestId(String pendingReqId) {
+ this.pendingRequestId = pendingReqId;
+
+ }
+
+ public final String getPendingRequestId() {
+ return pendingRequestId;
+ }
+
+ public final String getSSOSessionIdentifier() {
+ return this.ssoSessionId;
+ }
+
+ public final void setSSOSessionIdentifier(String internalSSOSessionId) {
+ this.ssoSessionId = internalSSOSessionId;
+
+ }
+
+ public final Map<String, Object> genericFullDataStorage() {
+ return this.genericDataStorage;
+
+ }
+
+ public final ISPConfiguration getServiceProviderConfiguration() {
+ return this.spConfiguration;
+
+
+ }
+
+ public <T> T getServiceProviderConfiguration(final Class<T> decorator) {
+ if (this.spConfiguration != null) {
+ if (decorator.isAssignableFrom(this.spConfiguration.getClass())) {
+ return (T) this.spConfiguration;
+
+ } else
+ log.error("Can not decorate SP configuration by '" + decorator.getName() + "'.");
+ throw new RuntimeException("Can not decorate SP configuration by '" + decorator.getName() + "'.");
+
+ }
+
+ return null;
+
+ }
+
+ public void setOnlineApplicationConfiguration(ISPConfiguration spConfig) {
+ this.spConfiguration = spConfig;
+
+ }
+
+ public final String getUniqueTransactionIdentifier() {
+ return this.uniqueTransactionIdentifer;
+
+ }
+
+ public final String getUniqueSessionIdentifier() {
+ return this.uniqueSessionIdentifer;
+
+ }
+
+ public final String getProcessInstanceId() {
+ return this.processInstanceId;
+
+ }
+
+ public final void setUniqueTransactionIdentifier(String id) {
+ this.uniqueTransactionIdentifer = id;
+
+ }
+
+ public final void setUniqueSessionIdentifier(String id) {
+ this.uniqueSessionIdentifer = id;
+
+ }
+
+ public void setProcessInstanceId(String id) {
+ this.processInstanceId = id;
+
+ }
+
+ public final String getAuthURL() {
+ return this.idpAuthURL;
+ }
+
+ public final String getAuthURLWithOutSlash() {
+ if (this.idpAuthURL.endsWith("/"))
+ return this.idpAuthURL.substring(0, this.idpAuthURL.length()-1);
+ else
+ return this.idpAuthURL;
+
+ }
+
+ public final boolean isNeedAuthentication() {
+ return needAuthentication;
+ }
+
+ public final void setNeedAuthentication(boolean needAuthentication) {
+ this.needAuthentication = needAuthentication;
+ }
+
+ public final boolean isAuthenticated() {
+ return isAuthenticated;
+ }
+
+ public final void setAuthenticated(boolean isAuthenticated) {
+ this.isAuthenticated = isAuthenticated;
+ }
+
+ public final boolean needSingleSignOnFunctionality() {
+ return needSSO;
+ }
+ public final void setNeedSingleSignOnFunctionality(boolean needSSO) {
+ this.needSSO = needSSO;
+
+ }
+
+ public final boolean isNeedUserConsent() {
+ return this.needUserConsent;
+
+ }
+
+ public final void setNeedUserConsent(boolean needConsent) {
+ this.needUserConsent = needConsent;
+
+ }
+
+ public final boolean isAbortedByUser() {
+ return this.isAbortedByUser;
+ }
+
+ public final void setAbortedByUser(boolean isAborted) {
+ this.isAbortedByUser = isAborted;
+
+ }
+
+ public final Object getGenericData(String key) {
+ if (StringUtils.isNotEmpty(key)) {
+ return genericDataStorage.get(key);
+
+ }
+
+ log.info("Can not load generic request-data with key='null'");
+ return null;
+ }
+
+ public final <T> T getGenericData(String key, final Class<T> clazz) {
+ if (StringUtils.isNotEmpty(key)) {
+ Object data = genericDataStorage.get(key);
+
+ if (data == null)
+ return null;
+
+ try {
+ @SuppressWarnings("unchecked")
+ T test = (T) data;
+ return test;
+
+ } catch (Exception e) {
+ log.warn("Generic request-data object can not be casted to requested type", e);
+ return null;
+
+ }
+
+ }
+
+ log.info("Can not load generic request-data with key='null'");
+ return null;
+
+ }
+
+ @Override
+ public final void setGenericDataToSession(String key, Object object) throws EAAFStorageException {
+ if (StringUtils.isEmpty(key)) {
+ log.info("Generic request-data can not be stored with a 'null' key");
+ throw new EAAFStorageException("Generic request-data can not be stored with a 'null' key", null);
+
+ }
+
+ if (object != null) {
+ if (!Serializable.class.isInstance(object)) {
+ log.warn("Generic request-data can only store objects which implements the 'Seralizable' interface");
+ throw new EAAFStorageException("Generic request-data can only store objects which implements the 'Seralizable' interface", null);
+
+ }
+ }
+
+ if (genericDataStorage.containsKey(key))
+ log.trace("Overwrite generic request-data with key:" + key);
+ else
+ log.trace("Add generic request-data with key:" + key + " to session.");
+
+ genericDataStorage.put(key, object);
+
+ }
+
+ @Override
+ public final void setGenericDataToSession(Map<String, Object> map) throws EAAFStorageException {
+ if (map == null) {
+ log.info("Generic request-data can not be stored with a 'null' map");
+ throw new EAAFStorageException("Generic request-data can not be stored with a 'null' map", null);
+
+ }
+
+ //validate and store values
+ for (Entry<String, Object> el : map.entrySet())
+ setGenericDataToSession(el.getKey(), el.getValue());
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/FinalizeAuthenticationTask.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/FinalizeAuthenticationTask.java
new file mode 100644
index 00000000..4ab63503
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/FinalizeAuthenticationTask.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.controller.tasks;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+
+/**
+ * @author tlenz
+ *
+ */
+@Component("FinalizeAuthenticationTask")
+public class FinalizeAuthenticationTask extends AbstractAuthServletTask {
+
+ private static final Logger log = LoggerFactory.getLogger(FinalizeAuthenticationTask.class);
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ public void execute(ExecutionContext executionContext,
+ HttpServletRequest request, HttpServletResponse response)
+ throws TaskExecutionException {
+
+ try {
+ //set pending request to authenticated
+ pendingReq.setAuthenticated(true);
+ requestStoreage.storePendingRequest(pendingReq);
+
+ log.info("AuthProcess finished. Redirect to Protocol Dispatcher.");
+ performRedirectToProtocolFinialization(pendingReq, response);
+
+ } catch (EAAFException e) {
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ } catch (Exception e) {
+ log.warn("FinalizeAuthenticationTask has an internal error", e);
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ } finally {
+ executionContext.remove(EAAFConstants.PROCESS_ENGINE_PENDINGREQUESTID);
+
+ }
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/RestartAuthProzessManagement.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/RestartAuthProzessManagement.java
new file mode 100644
index 00000000..2e5f49ed
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/RestartAuthProzessManagement.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.controller.tasks;
+
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.ModuleRegistration;
+import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl;
+import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl;
+
+/**
+ * @author tlenz
+ *
+ */
+@Component("RestartAuthProzessManagement")
+public class RestartAuthProzessManagement extends AbstractAuthServletTask {
+ private static final Logger log = LoggerFactory.getLogger(RestartAuthProzessManagement.class);
+
+ @Autowired ProcessEngine processEngine;
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
+ throws TaskExecutionException {
+ try {
+ //create a new execution context and copy all elements to new context
+ ExecutionContext newec = new ExecutionContextImpl();
+ Set<String> entries = executionContext.keySet();
+ for (String key : entries) {
+ newec.put(key, executionContext.get(key));
+
+ }
+
+ log.debug("Select new auth.-process and restart restart process-engine ... ");
+
+ // select and create new process instance
+ String processDefinitionId = ModuleRegistration.getInstance().selectProcess(newec);
+ if (processDefinitionId == null) {
+ log.warn("No suitable authentication process found for SessionID " + pendingReq.getPendingRequestId());
+ throw new EAAFException("process.02", new Object[] { pendingReq.getPendingRequestId()},
+ "No suitable authentication process found for SessionID \" + pendingReq.getPendingRequestId()");
+ }
+
+ String processInstanceId = processEngine.createProcessInstance(processDefinitionId, newec);
+
+ // keep process instance id in moa session
+ ((RequestImpl)pendingReq).setProcessInstanceId(processInstanceId);
+
+ // make sure pending request has been persisted before running the process
+ try {
+ requestStoreage.storePendingRequest(pendingReq);
+
+ } catch (EAAFException e) {
+ log.error("Database Error! MOASession is not stored!");
+ throw new EAAFException("init.04", new Object[] { pendingReq.getPendingRequestId() },
+ "Database Error! MOASession is not stored!");
+
+ }
+
+ log.info("Restart process-engine with auth.process:" + processDefinitionId);
+
+ // start process
+ processEngine.start(pendingReq);
+
+
+ } catch (EAAFException e) {
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ } catch (Exception e) {
+ log.warn("RestartAuthProzessManagement has an internal error", e);
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ }
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExecutionContextImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExecutionContextImpl.java
new file mode 100644
index 00000000..05fe030d
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExecutionContextImpl.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.process;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import at.gv.egiz.eaaf.core.api.idp.process.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExpressionEvaluationContextImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExpressionEvaluationContextImpl.java
new file mode 100644
index 00000000..5a85487f
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExpressionEvaluationContextImpl.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.process;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.idp.process.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java
new file mode 100644
index 00000000..2c715b94
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.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 at.gv.egiz.eaaf.core.impl.idp.process.model.EndEvent;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessDefinition;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessNode;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.StartEvent;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.TaskInfo;
+import at.gv.egiz.eaaf.core.impl.idp.process.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://reference.e-government.gv.at/namespace/moa/process/definition/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("/process/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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParserException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParserException.java
new file mode 100644
index 00000000..1ea811c6
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParserException.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java
new file mode 100644
index 00000000..b5028542
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java
@@ -0,0 +1,424 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.process;
+
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+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 org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluationContext;
+import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluator;
+import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine;
+import at.gv.egiz.eaaf.core.api.idp.process.ProcessInstanceStoreDAO;
+import at.gv.egiz.eaaf.core.api.idp.process.Task;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.ProcessExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.process.dao.ProcessInstanceStore;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.EndEvent;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessDefinition;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessNode;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.StartEvent;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.TaskInfo;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.Transition;
+
+/**
+ * Process engine implementation allowing starting and continuing processes as well as providing means for cleanup actions.
+ */
+public class ProcessEngineImpl implements ProcessEngine {
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+ @Autowired ProcessInstanceStoreDAO piStoreDao;
+ @Autowired ApplicationContext context;
+
+ private ProcessDefinitionParser pdp = new ProcessDefinitionParser();
+
+ private Map<String, ProcessDefinition> processDefinitions = new ConcurrentHashMap<String, ProcessDefinition>();
+
+ private final static String MDC_CTX_PI_NAME = "processInstanceId";
+ private final static String MDC_CTX_TASK_NAME = "taskId";
+
+ private ExpressionEvaluator transitionConditionExpressionEvaluator;
+
+ @Override
+ public void registerProcessDefinition(ProcessDefinition processDefinition) {
+ log.info("Registering process definition '{}'.", processDefinition.getId());
+ processDefinitions.put(processDefinition.getId(), processDefinition);
+ }
+
+ @Override
+ public String registerProcessDefinition(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException{
+ ProcessDefinition pd = pdp.parse(processDefinitionInputStream);
+ registerProcessDefinition(pd);
+ return pd.getId();
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * 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 String 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());
+
+ try {
+ saveOrUpdateProcessInstance(pi);
+
+ } catch (EAAFException e) {
+ throw new ProcessExecutionException("Unable to persist process instance.", e);
+ }
+
+ return pi.getId();
+ }
+
+ @Override
+ public String createProcessInstance(String processDefinitionId) throws ProcessExecutionException {
+ return createProcessInstance(processDefinitionId, null);
+ }
+
+ @Override
+ public void start(IRequest pendingReq) throws ProcessExecutionException {
+ try {
+ if (StringUtils.isEmpty(pendingReq.getProcessInstanceId())) {
+ log.error("Pending-request with id:" + pendingReq.getPendingRequestId()
+ + " includes NO 'ProcessInstanceId'");
+ throw new ProcessExecutionException("Pending-request with id:" + pendingReq.getPendingRequestId()
+ + " includes NO 'ProcessInstanceId'");
+ }
+
+ ProcessInstance pi = loadProcessInstance(pendingReq.getProcessInstanceId());
+
+ if (pi == null ) {
+ throw new ProcessExecutionException("Process instance '" + pendingReq.getProcessInstanceId() + "' does not exist.");
+
+ }
+
+ MDC.put(MDC_CTX_PI_NAME, pi.getId());
+
+ 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, pendingReq);
+
+ //store ProcessInstance if it is not already ended
+ if (!ProcessInstanceState.ENDED.equals(pi.getState()))
+ saveOrUpdateProcessInstance(pi);
+
+ } catch (EAAFException e) {
+ throw new ProcessExecutionException("Unable to load/save process instance.", e);
+
+ } finally {
+ MDC.remove(MDC_CTX_PI_NAME);
+ }
+ }
+
+ @Override
+ public void signal(IRequest pendingReq) throws ProcessExecutionException {
+
+ try {
+ if (StringUtils.isEmpty(pendingReq.getProcessInstanceId())) {
+ log.error("Pending-request with id:" + pendingReq.getPendingRequestId()
+ + " includes NO 'ProcessInstanceId'");
+ throw new ProcessExecutionException("Pending-request with id:" + pendingReq.getPendingRequestId()
+ + " includes NO 'ProcessInstanceId'");
+ }
+
+ ProcessInstance pi = loadProcessInstance(pendingReq.getProcessInstanceId());
+
+ if (pi == null ) {
+ throw new ProcessExecutionException("Process instance '" + pendingReq.getProcessInstanceId() + "' does not exist.");
+
+ }
+
+ MDC.put(MDC_CTX_PI_NAME, pi.getId());
+
+ 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);
+
+ //put pending-request ID on execution-context because it could be changed
+ pi.getExecutionContext().put(EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReq.getPendingRequestId());
+
+ execute(pi, pendingReq);
+
+ //store ProcessInstance if it is not already ended
+ if (!ProcessInstanceState.ENDED.equals(pi.getState()))
+ saveOrUpdateProcessInstance(pi);
+
+ } catch (EAAFException e) {
+ throw new ProcessExecutionException("Unable to load/save process instance.", e);
+
+ } finally {
+ MDC.remove(MDC_CTX_PI_NAME);
+ }
+ }
+
+
+ /**
+ * Instantiates 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);
+ Object instanceClass = null;
+ try {
+ instanceClass = context.getBean(clazz);
+
+ } catch (Exception e) {
+ throw new ProcessExecutionException("Unable to get class '" + clazz + "' associated with task '" + ti.getId() + "' .", e);
+
+ }
+ if (instanceClass == null || !(instanceClass instanceof Task)) {
+ throw new ProcessExecutionException("Class '" + clazz + "' associated with task '" + ti.getId() + "' is not assignable to " + Task.class.getName() + ".");
+
+ }
+ try {
+ task = (Task) instanceClass;
+
+ } 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.
+ * @param pendingReq
+ * @throws ProcessExecutionException Thrown in case of error.
+ */
+ private void execute(final ProcessInstance pi, IRequest pendingReq) 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());
+ pendingReq = task.execute(pendingReq, 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());
+
+ try {
+ piStoreDao.remove(pi.getId());
+
+ } catch (EAAFException e) {
+ throw new ProcessExecutionException("Unable to remove process instance.", e);
+
+ }
+ 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, pendingReq);
+ }
+ }
+
+ @Override
+ public ProcessInstance getProcessInstance(String processInstanceId) {
+
+ ProcessInstance processInstance;
+ try {
+ processInstance = loadProcessInstance(processInstanceId);
+
+ } catch (EAAFException e) {
+ throw new RuntimeException("The process instance '" + processInstanceId + "' could not be retrieved.", e);
+ }
+
+ if (processInstance == null) {
+ throw new IllegalArgumentException("The process instance '" + processInstanceId + "' does not/no longer exist.");
+ }
+
+ return processInstance;
+ }
+
+ /**
+ * Persists a {@link ProcessInstance} to the database.
+ * @param processInstance The object to persist.
+ * @throws MOADatabaseException Thrown if an error occurs while accessing the database.
+ */
+ private void saveOrUpdateProcessInstance(ProcessInstance processInstance) throws EAAFException {
+ ProcessInstanceStore store = new ProcessInstanceStore();
+
+ ExecutionContext ctx = processInstance.getExecutionContext();
+
+ Map<String, Serializable> ctxData = new HashMap<String, Serializable>();
+ for (String key : ctx.keySet()) {
+ ctxData.put(key, ctx.get(key));
+ }
+ store.setExecutionContextData(ctxData);
+
+ store.setNextTaskId(processInstance.getNextId());
+ store.setProcessDefinitionId(processInstance.getProcessDefinition().getId());
+
+ store.setProcessInstanceId(processInstance.getId());
+ store.setProcessState(processInstance.getState());
+
+ piStoreDao.saveOrUpdate(store);
+ }
+
+ /**
+ * Load a {@link ProcessInstance} with a certain id from the database.
+ * @param processInstanceId The process instance id
+ * @return The process instance corresponding to the id or {@code null} if no such object is found.
+ * @throws MOADatabaseException Thrown if an error occurs while accessing the database.
+ */
+ private ProcessInstance loadProcessInstance(String processInstanceId) throws EAAFException {
+
+ ProcessInstanceStore piStore = piStoreDao.load(processInstanceId);
+
+ if (piStore == null) {
+ return null;
+ }
+
+ ExecutionContext executionContext = new ExecutionContextImpl(piStore.getProcessInstanceId());
+
+ Map<String, Serializable> executionContextData = piStore.getExecutionContextData();
+ for (String key : executionContextData.keySet()) {
+ executionContext.put(key, executionContextData.get(key));
+ }
+
+ ProcessInstance pi = new ProcessInstance(processDefinitions.get(piStore.getProcessDefinitionId()), executionContext);
+ pi.setNextId(piStore.getNextTaskId());
+ pi.setState(piStore.getProcessState());
+
+ return pi;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.process.ProcessEngine#deleteProcessInstance(java.lang.String)
+ */
+ @Override
+ public void deleteProcessInstance(String processInstanceId) throws ProcessExecutionException {
+ if (StringUtils.isEmpty(processInstanceId)) {
+ throw new ProcessExecutionException("Unable to remove process instance: ProcessInstanceId is empty");
+
+ }
+
+ try {
+ piStoreDao.remove(processInstanceId);
+
+ } catch (EAAFException e) {
+ throw new ProcessExecutionException("Unable to remove process instance.", e);
+
+ }
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstance.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstance.java
new file mode 100644
index 00000000..ab6f7916
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstance.java
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.process;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.time.DurationFormatUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessDefinition;
+import at.gv.egiz.eaaf.core.impl.idp.process.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;
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+ /**
+ * 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 be newly generated if it is {@code null} in the execution context.
+ *
+ * @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();
+ if (executionContext == null) {
+ executionContext = new ExecutionContextImpl();
+ }
+ if (executionContext.getProcessInstanceId() == null) {
+ String pdIdLocalPart = RandomStringUtils.random(RND_ID_LENGTH, 0, 0, true, true, null,
+ SecureRandomHolder.getInstance());
+ executionContext.setProcessInstanceId(this.processDefinition.getId() + "-" + pdIdLocalPart);
+ } else {
+ log.debug("Using process instance id from execution context.");
+ }
+ log.debug("Creating process instance with id '{}'.", executionContext.getProcessInstanceId());
+ 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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstanceState.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstanceState.java
new file mode 100644
index 00000000..cfb5479b
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstanceState.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStore.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStore.java
new file mode 100644
index 00000000..1ac65e10
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStore.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.process.dao;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import at.gv.egiz.eaaf.core.impl.idp.process.ProcessInstanceState;
+
+public class ProcessInstanceStore implements Serializable{
+
+ private static final long serialVersionUID = -6147519767313903808L;
+
+ /**
+ * A process instance identifier qualifies as natural primary key by satisfying these requirements
+ * ("unique, constant, required"):
+ * <ul>
+ * <li>unique value</li>
+ * <li>never changes (immutable)</li>
+ * <li>never {@code null}</li>
+ * </ul>
+ */
+
+ private String processInstanceId;
+
+ private String processDefinitionId;
+
+ private String nextTaskId;
+
+ private ProcessInstanceState processState;
+
+ private Map<String, Serializable> executionContextData;
+
+ public String getProcessInstanceId() {
+ return processInstanceId;
+ }
+
+ public String getProcessDefinitionId() {
+ return processDefinitionId;
+ }
+
+ public String getNextTaskId() {
+ return nextTaskId;
+ }
+
+ public ProcessInstanceState getProcessState() {
+ return processState;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Map<String, Serializable> getExecutionContextData() {
+ return executionContextData;
+ }
+
+ public void setProcessInstanceId(String processInstanceId) {
+ this.processInstanceId = processInstanceId;
+ }
+
+ public void setProcessDefinitionId(String processDefinitionId) {
+ this.processDefinitionId = processDefinitionId;
+ }
+
+ public void setNextTaskId(String nextTaskId) {
+ this.nextTaskId = nextTaskId;
+ }
+
+ public void setProcessState(ProcessInstanceState processState) {
+ this.processState = processState;
+ }
+
+ public void setExecutionContextData(Map<String, Serializable> executionContextData) {
+ this.executionContextData = executionContextData;
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDAOImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDAOImpl.java
new file mode 100644
index 00000000..be80a629
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDAOImpl.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.process.dao;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import at.gv.egiz.eaaf.core.api.idp.process.ProcessInstanceStoreDAO;
+import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+
+/**
+ * Database backed implementation of the {@link ProcessInstanceStoreDAO}
+ * interface.
+ */
+@Service("ProcessInstanceStoreage")
+public class ProcessInstanceStoreDAOImpl implements ProcessInstanceStoreDAO {
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+ @Autowired ITransactionStorage transactionStorage;
+
+ @Override
+ public void saveOrUpdate(ProcessInstanceStore pIStore) throws EAAFException {
+ try {
+ transactionStorage.put(pIStore.getProcessInstanceId(), pIStore, -1);
+ log.debug("Store process instance with='{}' in the database.", pIStore.getProcessInstanceId());
+
+ } catch (EAAFException e) {
+ log.warn("ProcessInstanceStore could not be persisted to the database.");
+ throw e;
+ }
+ }
+
+ @Override
+ public ProcessInstanceStore load(String processInstanceId) throws EAAFException {
+ log.debug("Retrieve the ProcessInstanceStore for id='{}' from the database.", processInstanceId);
+ ProcessInstanceStore result = null;
+ try {
+ result = transactionStorage.get(processInstanceId, ProcessInstanceStore.class);
+
+ } catch (Exception e) {
+ log.error("There are multiple persisted processes with the same process instance id '{}'",
+ processInstanceId);
+
+ throw e;
+ }
+
+ if (result != null) {
+ log.debug("Found process instance store for instance '{}'.", processInstanceId);
+
+ } else {
+ log.debug("Unable to find process instance store for instance '{}'.", processInstanceId);
+
+ }
+
+ return result;
+ }
+
+ @Override
+ public void remove(String processInstanceId) throws EAAFException {
+
+ log.debug("Delete the ProcessInstanceStore for id='{}' from the database.", processInstanceId);
+
+ if (transactionStorage.containsKey(processInstanceId))
+ transactionStorage.remove(processInstanceId);
+ else
+ log.trace("ProcessInstanceStore for id='{}' was not found and could therefore not be deleted.", processInstanceId);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/EndEvent.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/EndEvent.java
new file mode 100644
index 00000000..a8b757e3
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/EndEvent.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessDefinition.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessDefinition.java
new file mode 100644
index 00000000..af4c0a1f
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessDefinition.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.process.model;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import at.gv.egiz.eaaf.core.impl.idp.process.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessNode.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessNode.java
new file mode 100644
index 00000000..e1109336
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessNode.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.process.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import at.gv.egiz.eaaf.core.impl.idp.process.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/StartEvent.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/StartEvent.java
new file mode 100644
index 00000000..3d3111c2
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/StartEvent.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/TaskInfo.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/TaskInfo.java
new file mode 100644
index 00000000..b7171236
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/TaskInfo.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.process.model;
+
+import java.io.Serializable;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+import at.gv.egiz.eaaf.core.api.idp.process.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/Transition.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/Transition.java
new file mode 100644
index 00000000..7ac26c20
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/Transition.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.process.model;
+
+import java.io.Serializable;
+
+import at.gv.egiz.eaaf.core.impl.idp.process.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/spring/SpringExpressionEvaluator.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/spring/SpringExpressionEvaluator.java
new file mode 100644
index 00000000..d301b77e
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/spring/SpringExpressionEvaluator.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.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 at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluationContext;
+import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluator;
+import at.gv.egiz.eaaf.core.impl.idp.process.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractAuthSourceServlet.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractAuthSourceServlet.java
new file mode 100644
index 00000000..095c3439
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractAuthSourceServlet.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.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 at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine;
+import at.gv.egiz.eaaf.core.impl.idp.process.ProcessInstance;
+
+/**
+ * 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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractTask.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractTask.java
new file mode 100644
index 00000000..446bf690
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractTask.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.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 at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.idp.process.Task;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+
+/**
+ * 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>
+ * ...
+ * &lt;filter&gt;
+ * &lt;filter-name&gt;requestContextFilter&lt;/filter-name&gt;
+ * &lt;filter-class&gt;org.springframework.web.filter.RequestContextFilter&lt;/filter-class&gt;
+ * &lt;/filter&gt;
+ * &lt;filter-mapping&gt;
+ * &lt;filter-name&gt;requestContextFilter&lt;/filter-name&gt;
+ * &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
+ * &lt;/filter-mapping&gt;
+ * ...
+ * </pre>
+ *
+ * @author tknall
+ * @author tlenz
+ *
+ */
+public abstract class AbstractTask 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 TaskExecutionException;
+
+ /**
+ * Executes the task providing the underlying {@link ExecutionContext} {@code executionContext}
+ * and the {@link IRequest} {@code pendingReq }as well as the
+ * respective {@link HttpServletRequest} and {@link HttpServletResponse}.
+ *
+ * This method sets the pending-request object of the task implementation and starts the
+ * {@code execute} method of the task
+ *
+ * @param pendingReq The pending-request object (never {@code null}).
+ * @param executionContext The execution context (never {@code null}).
+ * @param request The HttpServletRequest (never {@code null}).
+ * @param response The HttpServletResponse (never {@code null}).
+ * @return The pending-request object, because Process-management works recursive
+ *
+ * @throws IllegalStateException
+ * Thrown in case the task is being run within the required environment. Refer to javadoc for
+ * further information.
+ * @throws Exception
+ * Thrown in case of error executing the task.
+ */
+ protected abstract IRequest internalExecute(IRequest pendingReq, ExecutionContext executionContext, HttpServletRequest request,
+ HttpServletResponse response) throws TaskExecutionException;
+
+ @Override
+ public IRequest execute(IRequest pendingReq, ExecutionContext executionContext) throws TaskExecutionException {
+ 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.");
+ }
+ return internalExecute(pendingReq, executionContext, request, response);
+ } else {
+ throw new IllegalStateException("Task needs to be executed within a Spring web environment.");
+ }
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/SpringWebExpressionEvaluator.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/SpringWebExpressionEvaluator.java
new file mode 100644
index 00000000..229735e3
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/SpringWebExpressionEvaluator.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.process.springweb;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang3.ArrayUtils;
+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 at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluationContext;
+import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluator;
+import at.gv.egiz.eaaf.core.impl.idp.process.model.Transition;
+
+/**
+ * Expression evaluator for processing {@link Transition} conditions allowing to
+ * <ul>
+ * <li>reference Spring beans from the application context using {@code @myBeanName...},</li>
+ * <li>{@link ExecutionContext} properties using {@code ctx['property']},</li>
+ * <li>Multi valued {@link HttpServletRequest} parameters using {@code requestParameters['foo']} (keep in mind that this
+ * expression returns an array of String values) and</li>
+ * <li>Single valued {@link HttpServletRequest} parameters using {@code requestParameter['foo']}</li>
+ * </ul>
+ *
+ * @author tknall
+ *
+ */
+public class SpringWebExpressionEvaluator implements ExpressionEvaluator {
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+ private ExpressionParser parser = new SpelExpressionParser();
+ private StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
+
+ @Autowired(required = false)
+ private ApplicationContext ctx;
+
+ @Autowired(required = false)
+ private HttpServletRequest request;
+
+ @PostConstruct
+ private void init() {
+ if (ctx != null) {
+ evaluationContext.setBeanResolver(new BeanFactoryResolver(ctx));
+ }
+ }
+
+ /**
+ * Evaluation context that provides access to {@link HttpServletRequest} parameters using
+ * {@code requestParameter['foo']} for single value parameters or {@code requestParameters['foo']} for multi value
+ * parameters. Basic calls to {@code ctx} will be delegated.
+ *
+ * @author tknall
+ *
+ */
+ private class SpringWebExpressionEvaluationContext implements ExpressionEvaluationContext {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new expression evaluation context, providing access to HttpServletRequest parameter(s).
+ *
+ * @param delegate
+ * The original {@link ExpressionEvaluationContext} to be delegated to for {@code ctx['foo']}
+ * expressions.
+ */
+ public SpringWebExpressionEvaluationContext(ExpressionEvaluationContext delegate) {
+ this.delegate = delegate;
+ }
+
+ private ExpressionEvaluationContext delegate;
+
+ @Override
+ public Map<String, Serializable> getCtx() {
+ return delegate.getCtx();
+ }
+
+ @SuppressWarnings("unused")
+ public Map<String, String> getRequestParameter() {
+ if (request != null) {
+ Map<String, String> singleValueMap = new HashMap<String, String>();
+ Iterator<Entry<String, String[]>> it = request.getParameterMap().entrySet().iterator();
+ while (it.hasNext()) {
+ Entry<String, String[]> entry = it.next();
+ if (ArrayUtils.isNotEmpty(entry.getValue())) {
+ singleValueMap.put(entry.getKey(), entry.getValue()[0]);
+ }
+ }
+ return singleValueMap;
+ } else {
+ return Collections.<String, String> emptyMap();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public Map<String, String[]> getRequestParameters() {
+ if (request != null) {
+ return request.getParameterMap();
+ } else {
+ return Collections.<String, String[]> emptyMap();
+ }
+ }
+
+ }
+
+ @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 = null;
+ try {
+ result = expr.getValue(evaluationContext, new SpringWebExpressionEvaluationContext(expressionContext),
+ Boolean.class);
+ if (result == null) {
+ log.warn("Evaluation of '{}' results in null-value.", expression);
+ } else {
+ log.debug("Expression '{}' -> {}", expression, result);
+ }
+ } catch (Exception e) {
+ log.warn("Expression '{}' could not be processed.", expression, e);
+ }
+
+ return BooleanUtils.isTrue(result);
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/support/SecureRandomHolder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/support/SecureRandomHolder.java
new file mode 100644
index 00000000..0f581dae
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/support/SecureRandomHolder.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.idp.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/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/logging/DummyRevisionsLogger.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/logging/DummyRevisionsLogger.java
new file mode 100644
index 00000000..5b6b8146
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/logging/DummyRevisionsLogger.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.logging;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger;
+
+public class DummyRevisionsLogger implements IRevisionLogger {
+ private static final Logger log = LoggerFactory.getLogger(DummyStatisticLogger.class);
+
+
+ @Override
+ public void logEvent(ISPConfiguration oaConfig, int eventCode, String message) {
+ log.trace("Dummy-logEventOperation");
+
+ }
+
+ @Override
+ public void logEvent(int eventCode, String message) {
+ log.trace("Dummy-logEventOperation");
+
+ }
+
+ @Override
+ public void logEvent(String sessionID, String transactionID, int eventCode, String message) {
+ log.trace("Dummy-logEventOperation");
+
+ }
+
+ @Override
+ public void logEvent(String sessionID, String transactionID, int eventCode) {
+ log.trace("Dummy-logEventOperation");
+
+ }
+
+ @Override
+ public void logEvent(IRequest pendingRequest, int eventCode) {
+ log.trace("Dummy-logEventOperation");
+
+ }
+
+ @Override
+ public void logEvent(IRequest pendingRequest, int eventCode, String message) {
+ log.trace("Dummy-logEventOperation");
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/logging/DummyStatisticLogger.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/logging/DummyStatisticLogger.java
new file mode 100644
index 00000000..20f58b14
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/logging/DummyStatisticLogger.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.logging;
+
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.logging.IStatisticLogger;
+
+@Service("DummyStatisticLogger")
+public class DummyStatisticLogger implements IStatisticLogger{
+ private static final Logger log = LoggerFactory.getLogger(DummyStatisticLogger.class);
+
+ @Override
+ public void logSuccessOperation(IRequest protocolRequest,
+ IAuthData authData, boolean isSSOSession) {
+ log.trace("Dummy-logSuccessOperation");
+ }
+
+ @Override
+ public void logErrorOperation(Throwable throwable) {
+ log.trace("Dummy-logErrorOperation");
+ }
+
+ @Override
+ public void logErrorOperation(Throwable throwable, IRequest errorRequest) {
+ log.trace("Dummy-logErrorOperation");
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.advancedlogging.IStatisticLogger#testConnection()
+ */
+ @Override
+ public void internalTesting() throws Exception {
+ log.trace("Dummy-logErrorOperation");
+
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java
new file mode 100644
index 00000000..f28700a1
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java
@@ -0,0 +1,1243 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.xerces.parsers.DOMParser;
+import org.apache.xerces.parsers.SAXParser;
+import org.apache.xerces.parsers.XMLGrammarPreparser;
+import org.apache.xerces.util.SymbolTable;
+import org.apache.xerces.util.XMLGrammarPoolImpl;
+import org.apache.xerces.xni.grammars.XMLGrammarDescription;
+import org.apache.xerces.xni.grammars.XMLGrammarPool;
+import org.apache.xerces.xni.parser.XMLInputSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants;
+
+/**
+ * Various utility functions for handling XML DOM trees.
+ *
+ * The parsing methods in this class make use of some features internal to the
+ * Xerces DOM parser, mainly for performance reasons. As soon as JAXP
+ * (currently at version 1.2) is better at schema handling, it should be used as
+ * the parser interface.
+ *
+ */
+public class DOMUtils {
+ private static final Logger log = LoggerFactory.getLogger(DOMUtils.class);
+
+ /** Feature URI for namespace aware parsing. */
+ private static final String NAMESPACES_FEATURE =
+ "http://xml.org/sax/features/namespaces";
+ /** Feature URI for validating parsing. */
+ private static final String VALIDATION_FEATURE =
+ "http://xml.org/sax/features/validation";
+ /** Feature URI for schema validating parsing. */
+ private static final String SCHEMA_VALIDATION_FEATURE =
+ "http://apache.org/xml/features/validation/schema";
+ /** Feature URI for normalization of element/attribute values. */
+ private static final String NORMALIZED_VALUE_FEATURE =
+ "http://apache.org/xml/features/validation/schema/normalized-value";
+ /** Feature URI for parsing ignorable whitespace. */
+ private static final String INCLUDE_IGNORABLE_WHITESPACE_FEATURE =
+ "http://apache.org/xml/features/dom/include-ignorable-whitespace";
+ /** Feature URI for creating EntityReference nodes in the DOM tree. */
+ private static final String CREATE_ENTITY_REF_NODES_FEATURE =
+ "http://apache.org/xml/features/dom/create-entity-ref-nodes";
+ /** Property URI for providing external schema locations. */
+ private static final String EXTERNAL_SCHEMA_LOCATION_PROPERTY =
+ "http://apache.org/xml/properties/schema/external-schemaLocation";
+ /** Property URI for providing the external schema location for elements
+ * without a namespace. */
+ private static final String EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY =
+ "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";
+
+ private static final String EXTERNAL_GENERAL_ENTITIES_FEATURE =
+ "http://xml.org/sax/features/external-general-entities";
+
+ private static final String EXTERNAL_PARAMETER_ENTITIES_FEATURE =
+ "http://xml.org/sax/features/external-parameter-entities";
+
+ public static final String DISALLOW_DOCTYPE_FEATURE =
+ "http://apache.org/xml/features/disallow-doctype-decl";
+
+
+
+ /** Property URI for the Xerces grammar pool. */
+ private static final String GRAMMAR_POOL =
+ org.apache.xerces.impl.Constants.XERCES_PROPERTY_PREFIX
+ + org.apache.xerces.impl.Constants.XMLGRAMMAR_POOL_PROPERTY;
+ /** A prime number for initializing the symbol table. */
+ private static final int BIG_PRIME = 2039;
+ /** Symbol table for the grammar pool. */
+ private static SymbolTable symbolTable = new SymbolTable(BIG_PRIME);
+ /** Xerces schema grammar pool. */
+ private static XMLGrammarPool grammarPool = new XMLGrammarPoolImpl();
+ /** Set holding the NamespaceURIs of the grammarPool, to prevent multiple
+ * entries of same grammars to the pool */
+ private static Set grammarNamespaces;
+
+ static {
+ grammarPool.lockPool();
+ grammarNamespaces = new HashSet();
+ }
+
+ /**
+ * Preparse a schema and add it to the schema pool.
+ * The method only adds the schema to the pool if a schema having the same
+ * <code>systemId</code> (namespace URI) is not already present in the pool.
+ *
+ * @param inputStream An <code>InputStream</code> providing the contents of
+ * the schema.
+ * @param systemId The systemId (namespace URI) to use for the schema.
+ * @throws IOException An error occurred reading the schema.
+ */
+ public static void addSchemaToPool(InputStream inputStream, String systemId)
+ throws IOException {
+ XMLGrammarPreparser preparser;
+
+ if (!grammarNamespaces.contains(systemId)) {
+
+ grammarNamespaces.add(systemId);
+
+ // unlock the pool so that we can add another grammar
+ grammarPool.unlockPool();
+
+ // prepare the preparser
+ preparser = new XMLGrammarPreparser(symbolTable);
+ preparser.registerPreparser(XMLGrammarDescription.XML_SCHEMA, null);
+ preparser.setProperty(GRAMMAR_POOL, grammarPool);
+ preparser.setFeature(NAMESPACES_FEATURE, true);
+ preparser.setFeature(VALIDATION_FEATURE, true);
+
+ // add the grammar to the pool
+ preparser.preparseGrammar(
+ XMLGrammarDescription.XML_SCHEMA,
+ new XMLInputSource(null, systemId, null, inputStream, null));
+
+ // lock the pool again so that schemas are not added automatically
+ grammarPool.lockPool();
+ }
+ }
+
+ /**
+ * Parse an XML document from an <code>InputStream</code>.
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @param entityResolver An <code>EntityResolver</code> to resolve external
+ * entities (schemas and DTDs). If <code>null</code>, it will not be set.
+ * @param errorHandler An <code>ErrorHandler</code> to decide what to do
+ * with parsing errors. If <code>null</code>, it will not be set.
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocument(
+ InputStream inputStream,
+ boolean validating,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation,
+ EntityResolver entityResolver,
+ ErrorHandler errorHandler,
+ Map<String, Object> parserFeatures)
+ throws SAXException, IOException, ParserConfigurationException {
+
+ DOMParser parser;
+
+// class MyEntityResolver implements EntityResolver {
+//
+// public InputSource resolveEntity(String publicId, String systemId)
+// throws SAXException, IOException {
+// return new InputSource(new ByteArrayInputStream(new byte[0]));
+// }
+// }
+
+
+ //if Debug is enabled make a copy of inputStream to enable debug output in case of SAXException
+ byte buffer [] = null;
+ ByteArrayInputStream baStream = null;
+ if(true == log.isDebugEnabled()) {
+ buffer = IOUtils.toByteArray(inputStream);
+ baStream = new ByteArrayInputStream(buffer);
+
+ }
+
+
+
+ // create the DOM parser
+ if (symbolTable != null) {
+ parser = new DOMParser(symbolTable, grammarPool);
+ } else {
+ parser = new DOMParser();
+ }
+
+ // set parser features and properties
+ try {
+ parser.setFeature(NAMESPACES_FEATURE, true);
+ parser.setFeature(VALIDATION_FEATURE, validating);
+ parser.setFeature(SCHEMA_VALIDATION_FEATURE, validating);
+ parser.setFeature(NORMALIZED_VALUE_FEATURE, false);
+ parser.setFeature(INCLUDE_IGNORABLE_WHITESPACE_FEATURE, true);
+ parser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, false);
+ parser.setFeature(EXTERNAL_GENERAL_ENTITIES_FEATURE, false);
+ parser.setFeature(EXTERNAL_PARAMETER_ENTITIES_FEATURE, false);
+
+ //set external added parser features
+ if (parserFeatures != null) {
+ for (Entry<String, Object> el : parserFeatures.entrySet()) {
+ String key = el.getKey();
+ if (StringUtils.isNotEmpty(key)) {
+ Object value = el.getValue();
+ if (value != null && value instanceof Boolean)
+ parser.setFeature(key, (boolean)value);
+
+ else
+ log.warn("This XML parser only allows features with 'boolean' values");
+
+ } else
+ log.warn("Can not set 'null' feature to XML parser");
+ }
+ }
+
+ //fix XXE problem
+ //parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+
+
+ if (validating) {
+ if (externalSchemaLocations != null) {
+ parser.setProperty(
+ EXTERNAL_SCHEMA_LOCATION_PROPERTY,
+ externalSchemaLocations);
+ }
+ if (externalNoNamespaceSchemaLocation != null) {
+ parser.setProperty(
+ EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY,
+ externalNoNamespaceSchemaLocation);
+ }
+ }
+
+ // set entity resolver and error handler
+ if (entityResolver != null) {
+ parser.setEntityResolver(entityResolver);
+ }
+ if (errorHandler != null) {
+ parser.setErrorHandler(errorHandler);
+ }
+
+ // parse the document and return it
+ // if debug is enabled: use copy of strem (baStream) else use orig stream
+ if(null != baStream)
+ parser.parse(new InputSource(baStream));
+ else
+ parser.parse(new InputSource(inputStream));
+ } catch(SAXException e) {
+ if(true == log.isDebugEnabled() && null != buffer) {
+ String xmlContent = new String(buffer);
+ log.debug("SAXException in:\n" + xmlContent);
+ }
+ throw(e);
+ }
+
+ return parser.getDocument();
+ }
+
+ /**
+ * Parse an XML document from an <code>InputStream</code>.
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @param entityResolver An <code>EntityResolver</code> to resolve external
+ * entities (schemas and DTDs). If <code>null</code>, it will not be set.
+ * @param errorHandler An <code>ErrorHandler</code> to decide what to do
+ * with parsing errors. If <code>null</code>, it will not be set.
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocumentSimple(InputStream inputStream)
+ throws SAXException, IOException, ParserConfigurationException {
+
+ DOMParser parser;
+
+ parser = new DOMParser();
+ // set parser features and properties
+ parser.setFeature(NAMESPACES_FEATURE, true);
+ parser.setFeature(VALIDATION_FEATURE, false);
+ parser.setFeature(SCHEMA_VALIDATION_FEATURE, false);
+ parser.setFeature(NORMALIZED_VALUE_FEATURE, false);
+ parser.setFeature(INCLUDE_IGNORABLE_WHITESPACE_FEATURE, true);
+ parser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, false);
+
+ parser.parse(new InputSource(inputStream));
+
+ return parser.getDocument();
+ }
+
+
+ /**
+ * Parse an XML document from an <code>InputStream</code>.
+ *
+ * It uses a <code>MOAEntityResolver</code> as the <code>EntityResolver</code>
+ * and a <code>MOAErrorHandler</code> as the <code>ErrorHandler</code>.
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @param parserFeatures
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocument(
+ InputStream inputStream,
+ boolean validating,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation, Map<String, Object> parserFeatures)
+ throws SAXException, IOException, ParserConfigurationException {
+
+
+
+ return parseDocument(
+ inputStream,
+ validating,
+ externalSchemaLocations,
+ externalNoNamespaceSchemaLocation,
+ new EAAFDomEntityResolver(),
+ null,
+ parserFeatures);
+ }
+
+ /**
+ * Parse an XML document from a <code>String</code>.
+ *
+ * It uses a <code>MOAEntityResolver</code> as the <code>EntityResolver</code>
+ * and a <code>MOAErrorHandler</code> as the <code>ErrorHandler</code>.
+ *
+ * @param xmlString The <code>String</code> containing the XML document.
+ * @param encoding The encoding of the XML document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocument(
+ String xmlString,
+ String encoding,
+ boolean validating,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation,
+ Map<String, Object> parserFeatures)
+ throws SAXException, IOException, ParserConfigurationException {
+
+ InputStream in = new ByteArrayInputStream(xmlString.getBytes(encoding));
+ return parseDocument(
+ in,
+ validating,
+ externalSchemaLocations,
+ externalNoNamespaceSchemaLocation,
+ parserFeatures);
+ }
+
+
+ /**
+ * Parse an XML document from a <code>String</code>.
+ *
+ * It uses a <code>MOAEntityResolver</code> as the <code>EntityResolver</code>
+ * and a <code>MOAErrorHandler</code> as the <code>ErrorHandler</code>.
+ *
+ * @param xmlString The <code>String</code> containing the XML document.
+ * @param encoding The encoding of the XML document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocument(
+ String xmlString,
+ String encoding,
+ boolean validating,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation)
+ throws SAXException, IOException, ParserConfigurationException {
+
+ InputStream in = new ByteArrayInputStream(xmlString.getBytes(encoding));
+ return parseDocument(
+ in,
+ validating,
+ externalSchemaLocations,
+ externalNoNamespaceSchemaLocation,
+ null);
+ }
+
+ /**
+ * Parse an UTF-8 encoded XML document from a <code>String</code>.
+ *
+ * @param xmlString The <code>String</code> containing the XML document.
+ * @param validating If <code>true</code>, parse validating.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @return The parsed XML document as a DOM tree.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Document parseDocument(
+ String xmlString,
+ boolean validating,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation)
+ throws SAXException, IOException, ParserConfigurationException {
+
+ return parseDocument(
+ xmlString,
+ "UTF-8",
+ validating,
+ externalSchemaLocations,
+ externalNoNamespaceSchemaLocation);
+ }
+
+ /**
+ * A convenience method to parse an XML document validating.
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @return The root element of the parsed XML document.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Element parseXmlValidating(InputStream inputStream)
+ throws ParserConfigurationException, SAXException, IOException {
+ return DOMUtils
+ .parseDocument(inputStream, true, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, null, null)
+ .getDocumentElement();
+ }
+
+ /**
+ * A convenience method to parse an XML document validating.
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @param parserFeatures Set additional features to XML parser
+ * @return The root element of the parsed XML document.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Element parseXmlValidating(InputStream inputStream, Map<String, Object> parserFeatures)
+ throws ParserConfigurationException, SAXException, IOException {
+ return DOMUtils
+ .parseDocument(inputStream, true, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, null, parserFeatures)
+ .getDocumentElement();
+ }
+
+ /**
+ * A convenience method to parse an XML document non validating.
+ * This method disallow DocType declarations
+ *
+ * @param inputStream The <code>InputStream</code> containing the XML
+ * document.
+ * @return The root element of the parsed XML document.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * parser.
+ */
+ public static Element parseXmlNonValidating(InputStream inputStream)
+ throws ParserConfigurationException, SAXException, IOException {
+ return DOMUtils
+ .parseDocument(inputStream, false, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, null,
+ Collections.unmodifiableMap(new HashMap<String, Object>() {
+ private static final long serialVersionUID = 1L;
+ {
+ put(DOMUtils.DISALLOW_DOCTYPE_FEATURE, true);
+
+ }
+ })).getDocumentElement();
+ }
+
+ /**
+ * Schema validate a given DOM element.
+ *
+ * @param element The element to validate.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @return <code>true</code>, if the <code>element</code> validates against
+ * the schemas declared in it.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document from its
+ * serialized representation.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * @throws TransformerException An error occurred serializing the element.
+ */
+ public static boolean validateElement(
+ Element element,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation)
+ throws
+ ParserConfigurationException,
+ IOException,
+ SAXException,
+ TransformerException {
+
+ byte[] docBytes;
+ SAXParser parser;
+
+ // create the SAX parser
+ if (symbolTable != null) {
+ parser = new SAXParser(symbolTable, grammarPool);
+ } else {
+ parser = new SAXParser();
+ }
+
+ // serialize the document
+ docBytes = serializeNode(element, "UTF-8");
+
+ // set up parser features and attributes
+ parser.setFeature(NAMESPACES_FEATURE, true);
+ parser.setFeature(VALIDATION_FEATURE, true);
+ parser.setFeature(SCHEMA_VALIDATION_FEATURE, true);
+ parser.setFeature(EXTERNAL_GENERAL_ENTITIES_FEATURE, false);
+ parser.setFeature(DISALLOW_DOCTYPE_FEATURE, true);
+
+
+ if (externalSchemaLocations != null) {
+ parser.setProperty(
+ EXTERNAL_SCHEMA_LOCATION_PROPERTY,
+ externalSchemaLocations);
+ }
+ if (externalNoNamespaceSchemaLocation != null) {
+ parser.setProperty(
+ EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY,
+ "externalNoNamespaceSchemaLocation");
+ }
+
+ // set up entity resolver and error handler
+ parser.setEntityResolver(new EAAFDomEntityResolver());
+
+ // parse validating
+ parser.parse(new InputSource(new ByteArrayInputStream(docBytes)));
+ return true;
+ }
+
+
+ /**
+ * Schema validate a given DOM element.
+ *
+ * @param element The element to validate.
+ * @param externalSchemaLocations A <code>String</code> containing namespace
+ * URI to schema location pairs, the same way it is accepted by the <code>xsi:
+ * schemaLocation</code> attribute.
+ * @param externalNoNamespaceSchemaLocation The schema location of the
+ * schema for elements without a namespace, the same way it is accepted by the
+ * <code>xsi:noNamespaceSchemaLocation</code> attribute.
+ * @return <code>true</code>, if the <code>element</code> validates against
+ * the schemas declared in it.
+ * @throws SAXException An error occurred parsing the document.
+ * @throws IOException An error occurred reading the document from its
+ * serialized representation.
+ * @throws ParserConfigurationException An error occurred configuring the XML
+ * @throws TransformerException An error occurred serializing the element.
+ */
+ public static boolean validateElement(
+ Element element,
+ String externalSchemaLocations,
+ String externalNoNamespaceSchemaLocation,
+ EntityResolver entityResolver)
+ throws
+ ParserConfigurationException,
+ IOException,
+ SAXException,
+ TransformerException {
+
+ byte[] docBytes;
+ SAXParser parser;
+
+ // create the SAX parser
+ if (symbolTable != null) {
+ parser = new SAXParser(symbolTable, grammarPool);
+ } else {
+ parser = new SAXParser();
+ }
+
+ // serialize the document
+ docBytes = serializeNode(element, "UTF-8");
+
+ // set up parser features and attributes
+ parser.setFeature(NAMESPACES_FEATURE, true);
+ parser.setFeature(VALIDATION_FEATURE, true);
+ parser.setFeature(SCHEMA_VALIDATION_FEATURE, true);
+
+ if (externalSchemaLocations != null) {
+ parser.setProperty(
+ EXTERNAL_SCHEMA_LOCATION_PROPERTY,
+ externalSchemaLocations);
+ }
+ if (externalNoNamespaceSchemaLocation != null) {
+ parser.setProperty(
+ EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY,
+ "externalNoNamespaceSchemaLocation");
+ }
+
+ // set up entity resolver and error handler
+ parser.setEntityResolver(entityResolver);
+
+ // parse validating
+ parser.parse(new InputSource(new ByteArrayInputStream(docBytes)));
+ return true;
+ }
+
+ /**
+ * Serialize the given DOM node.
+ *
+ * The node will be serialized using the UTF-8 encoding.
+ *
+ * @param node The node to serialize.
+ * @return String The <code>String</code> representation of the given DOM
+ * node.
+ * @throws TransformerException An error occurred transforming the
+ * node to a <code>String</code>.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static String serializeNode(Node node)
+ throws TransformerException, IOException {
+ return new String(serializeNode(node, "UTF-8", false), "UTF-8");
+ }
+
+
+ /**
+ * Serialize the given DOM node.
+ *
+ * The node will be serialized using the UTF-8 encoding.
+ *
+ * @param node The node to serialize.
+ * @param omitXmlDeclaration The boolean value for omitting the XML Declaration.
+ * @return String The <code>String</code> representation of the given DOM
+ * node.
+ * @throws TransformerException An error occurred transforming the
+ * node to a <code>String</code>.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static String serializeNode(Node node, boolean omitXmlDeclaration)
+ throws TransformerException, IOException {
+ return new String(serializeNode(node, "UTF-8", omitXmlDeclaration), "UTF-8");
+ }
+
+ /**
+ * Serialize the given DOM node.
+ *
+ * The node will be serialized using the UTF-8 encoding.
+ *
+ * @param node The node to serialize.
+ * @param omitXmlDeclaration The boolean value for omitting the XML Declaration.
+ * @param lineSeperator Sets the line seperator String of the parser
+ * @return String The <code>String</code> representation of the given DOM
+ * node.
+ * @throws TransformerException An error occurred transforming the
+ * node to a <code>String</code>.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static String serializeNode(Node node, boolean omitXmlDeclaration, String lineSeperator)
+ throws TransformerException, IOException {
+ return new String(serializeNode(node, "UTF-8", omitXmlDeclaration, lineSeperator), "UTF-8");
+ }
+
+ /**
+ * Serialize the given DOM node to a byte array.
+ *
+ * @param node The node to serialize.
+ * @param xmlEncoding The XML encoding to use.
+ * @return The serialized node, as a byte array. Using a compatible encoding
+ * this can easily be converted into a <code>String</code>.
+ * @throws TransformerException An error occurred transforming the node to a
+ * byte array.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static byte[] serializeNode(Node node, String xmlEncoding)
+ throws TransformerException, IOException {
+ return serializeNode(node, xmlEncoding, false);
+ }
+
+ /**
+ * Serialize the given DOM node to a byte array.
+ *
+ * @param node The node to serialize.
+ * @param xmlEncoding The XML encoding to use.
+ * @param omitDeclaration The boolean value for omitting the XML Declaration.
+ * @return The serialized node, as a byte array. Using a compatible encoding
+ * this can easily be converted into a <code>String</code>.
+ * @throws TransformerException An error occurred transforming the node to a
+ * byte array.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static byte[] serializeNode(Node node, String xmlEncoding, boolean omitDeclaration)
+ throws TransformerException, IOException {
+ return serializeNode(node, xmlEncoding, omitDeclaration, null);
+ }
+
+
+ /**
+ * Serialize the given DOM node to a byte array.
+ *
+ * @param node The node to serialize.
+ * @param xmlEncoding The XML encoding to use.
+ * @param omitDeclaration The boolean value for omitting the XML Declaration.
+ * @param lineSeperator Sets the line seperator String of the parser
+ * @return The serialized node, as a byte array. Using a compatible encoding
+ * this can easily be converted into a <code>String</code>.
+ * @throws TransformerException An error occurred transforming the node to a
+ * byte array.
+ * @throws IOException An IO error occurred writing the node to a byte array.
+ */
+ public static byte[] serializeNode(Node node, String xmlEncoding, boolean omitDeclaration, String lineSeperator)
+ throws TransformerException, IOException {
+
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(16384);
+
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+ transformer.setOutputProperty(OutputKeys.ENCODING, xmlEncoding);
+ String omit = omitDeclaration ? "yes" : "no";
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, omit);
+ if (null!=lineSeperator) {
+ transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator", lineSeperator);//does not work for xalan <= 2.5.1
+ }
+ transformer.transform(new DOMSource(node), new StreamResult(bos));
+
+ bos.flush();
+ bos.close();
+
+ return bos.toByteArray();
+ }
+
+ /**
+ * Return the text that a node contains.
+ *
+ * This routine:
+ * <ul>
+ * <li>Ignores comments and processing instructions.</li>
+ * <li>Concatenates TEXT nodes, CDATA nodes, and the results recursively
+ * processing EntityRef nodes.</li>
+ * <li>Ignores any element nodes in the sublist. (Other possible options are
+ * to recurse into element sublists or throw an exception.)</li>
+ * </ul>
+ *
+ * @param node A DOM node from which to extract text.
+ * @return A String representing its contents.
+ */
+ public static String getText(Node node) {
+ if (!node.hasChildNodes()) {
+ return "";
+ }
+
+ StringBuffer result = new StringBuffer();
+ NodeList list = node.getChildNodes();
+
+ for (int i = 0; i < list.getLength(); i++) {
+ Node subnode = list.item(i);
+ if (subnode.getNodeType() == Node.TEXT_NODE) {
+ result.append(subnode.getNodeValue());
+ } else if (subnode.getNodeType() == Node.CDATA_SECTION_NODE) {
+ result.append(subnode.getNodeValue());
+ } else if (subnode.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
+ // Recurse into the subtree for text
+ // (and ignore comments)
+ result.append(getText(subnode));
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * Build the namespace prefix to namespace URL mapping in effect for a given
+ * node.
+ *
+ * @param node The context node for which build the map.
+ * @return The namespace prefix to namespace URL mapping (
+ * a <code>String</code> value to <code>String</code> value mapping).
+ */
+ public static Map getNamespaceDeclarations(Node node) {
+ Map nsDecls = new HashMap();
+ int i;
+
+ do {
+ if (node.hasAttributes()) {
+ NamedNodeMap attrs = node.getAttributes();
+
+ for (i = 0; i < attrs.getLength(); i++) {
+ Attr attr = (Attr) attrs.item(i);
+
+ // add prefix mapping if none exists
+ if ("xmlns".equals(attr.getPrefix())
+ || "xmlns".equals(attr.getName())) {
+
+ String nsPrefix =
+ attr.getPrefix() != null ? attr.getLocalName() : "";
+
+ if (nsDecls.get(nsPrefix) == null) {
+ nsDecls.put(nsPrefix, attr.getValue());
+ }
+ }
+ }
+ }
+ } while ((node = node.getParentNode()) != null);
+
+ return nsDecls;
+ }
+
+ /**
+ * Add all namespace declarations declared in the parent(s) of a given
+ * element and used in the subtree of the given element to the given element.
+ *
+ * @param context The element to which to add the namespaces.
+ */
+ public static void localizeNamespaceDeclarations(Element context) {
+ Node parent = context.getParentNode();
+
+ if (parent != null) {
+ Map namespaces = getNamespaceDeclarations(context.getParentNode());
+ Set nsUris = collectNamespaceURIs(context);
+ Iterator iter;
+
+ for (iter = namespaces.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry e = (Map.Entry) iter.next();
+
+ if (nsUris.contains(e.getValue())) {
+ String prefix = (String) e.getKey();
+ String nsUri = (String) e.getValue();
+ String nsAttrName = "".equals(prefix) ? "xmlns" : "xmlns:" + prefix;
+
+ context.setAttributeNS(XMLNamespaceConstants.XMLNS_NS_URI, nsAttrName, nsUri);
+ }
+ }
+ }
+ }
+
+ /**
+ * Collect all the namespace URIs used in the subtree of a given element.
+ *
+ * @param context The element that should be searched for namespace URIs.
+ * @return All namespace URIs used in the subtree of <code>context</code>,
+ * including the ones used in <code>context</code> itself.
+ */
+ public static Set collectNamespaceURIs(Element context) {
+ Set result = new HashSet();
+
+ collectNamespaceURIsImpl(context, result);
+ return result;
+ }
+
+ /**
+ * A recursive method to do the work of <code>collectNamespaceURIs</code>.
+ *
+ * @param context The context element to evaluate.
+ * @param result The result, passed as a parameter to avoid unnecessary
+ * instantiations of <code>Set</code>.
+ */
+ private static void collectNamespaceURIsImpl(Element context, Set result) {
+ NamedNodeMap attrs = context.getAttributes();
+ NodeList childNodes = context.getChildNodes();
+ String nsUri;
+ int i;
+
+ // add the namespace of the context element
+ nsUri = context.getNamespaceURI();
+ if (nsUri != null && nsUri != XMLNamespaceConstants.XMLNS_NS_URI) {
+ result.add(nsUri);
+ }
+
+ // add all namespace URIs from attributes
+ for (i = 0; i < attrs.getLength(); i++) {
+ nsUri = attrs.item(i).getNamespaceURI();
+ if (nsUri != null && nsUri != XMLNamespaceConstants.XMLNS_NS_URI) {
+ result.add(nsUri);
+ }
+ }
+
+ // add all namespaces from subelements
+ for (i = 0; i < childNodes.getLength(); i++) {
+ Node node = childNodes.item(i);
+
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ collectNamespaceURIsImpl((Element) node, result);
+ }
+ }
+ }
+
+ /**
+ * Check, that each attribute node in the given <code>NodeList</code> has its
+ * parent in the <code>NodeList</code> as well.
+ *
+ * @param nodes The <code>NodeList</code> to check.
+ * @return <code>true</code>, if each attribute node in <code>nodes</code>
+ * has its parent in <code>nodes</code> as well.
+ */
+ public static boolean checkAttributeParentsInNodeList(NodeList nodes) {
+ Set nodeSet = new HashSet();
+ int i;
+
+ // put the nodes into the nodeSet
+ for (i = 0; i < nodes.getLength(); i++) {
+ nodeSet.add(nodes.item(i));
+ }
+
+ // check that each attribute node's parent is in the node list
+ for (i = 0; i < nodes.getLength(); i++) {
+ Node n = nodes.item(i);
+
+ if (n.getNodeType() == Node.ATTRIBUTE_NODE) {
+ Attr attr = (Attr) n;
+ Element owner = attr.getOwnerElement();
+
+ if (owner == null) {
+ if (!isNamespaceDeclaration(attr)) {
+ return false;
+ }
+ }
+
+ if (!nodeSet.contains(owner) && !isNamespaceDeclaration(attr)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Convert an unstructured <code>NodeList</code> into a
+ * <code>DocumentFragment</code>.
+ *
+ * @param nodeList Contains the node list to be converted into a DOM
+ * DocumentFragment.
+ * @return the resulting DocumentFragment. The DocumentFragment will be
+ * backed by a new DOM Document, i.e. all noded of the node list will be
+ * cloned.
+ * @throws ParserConfigurationException An error occurred creating the
+ * DocumentFragment.
+ * @precondition The nodes in the node list appear in document order
+ * @precondition for each Attr node in the node list, the owning Element is
+ * in the node list as well.
+ * @precondition each Element or Attr node in the node list is namespace
+ * aware.
+ */
+ public static DocumentFragment nodeList2DocumentFragment(NodeList nodeList)
+ throws ParserConfigurationException {
+
+ DocumentBuilder builder =
+ DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ Document doc = builder.newDocument();
+ DocumentFragment result = doc.createDocumentFragment();
+
+ if (null == nodeList || nodeList.getLength() == 0) {
+ return result;
+ }
+
+ int currPos = 0;
+ currPos =
+ nodeList2DocumentFragment(nodeList, currPos, result, null, null) + 1;
+
+ while (currPos < nodeList.getLength()) {
+ currPos =
+ nodeList2DocumentFragment(nodeList, currPos, result, null, null) + 1;
+ }
+ return result;
+ }
+
+ /**
+ * Helper method for the <code>nodeList2DocumentFragment</code>.
+ *
+ * @param nodeList The <code>NodeList</code> to convert.
+ * @param currPos The current position in the <code>nodeList</code>.
+ * @param result The resulting <code>DocumentFragment</code>.
+ * @param currOrgElem The current original element.
+ * @param currClonedElem The current cloned element.
+ * @return The current position.
+ */
+ private static int nodeList2DocumentFragment(
+ NodeList nodeList,
+ int currPos,
+ DocumentFragment result,
+ Element currOrgElem,
+ Element currClonedElem) {
+
+ while (currPos < nodeList.getLength()) {
+ Node currentNode = nodeList.item(currPos);
+ switch (currentNode.getNodeType()) {
+ case Node.COMMENT_NODE :
+ case Node.PROCESSING_INSTRUCTION_NODE :
+ case Node.TEXT_NODE :
+ {
+ // Append current node either to resulting DocumentFragment or to
+ // current cloned Element
+ if (null == currClonedElem) {
+ result.appendChild(
+ result.getOwnerDocument().importNode(currentNode, false));
+ } else {
+ // Stop processing if current Node is not a descendant of
+ // current Element
+ if (!isAncestor(currOrgElem, currentNode)) {
+ return --currPos;
+ }
+
+ currClonedElem.appendChild(
+ result.getOwnerDocument().importNode(currentNode, false));
+ }
+ break;
+ }
+
+ case Node.ELEMENT_NODE :
+ {
+ Element nextCurrOrgElem = (Element) currentNode;
+ Element nextCurrClonedElem =
+ result.getOwnerDocument().createElementNS(
+ nextCurrOrgElem.getNamespaceURI(),
+ nextCurrOrgElem.getNodeName());
+
+ // Append current Node either to resulting DocumentFragment or to
+ // current cloned Element
+ if (null == currClonedElem) {
+ result.appendChild(nextCurrClonedElem);
+ currOrgElem = nextCurrOrgElem;
+ currClonedElem = nextCurrClonedElem;
+ } else {
+ // Stop processing if current Node is not a descendant of
+ // current Element
+ if (!isAncestor(currOrgElem, currentNode)) {
+ return --currPos;
+ }
+
+ currClonedElem.appendChild(nextCurrClonedElem);
+ }
+
+ // Process current Node (of type Element) recursively
+ currPos =
+ nodeList2DocumentFragment(
+ nodeList,
+ ++currPos,
+ result,
+ nextCurrOrgElem,
+ nextCurrClonedElem);
+
+ break;
+ }
+
+ case Node.ATTRIBUTE_NODE :
+ {
+ Attr currAttr = (Attr) currentNode;
+
+ // GK 20030411: Hack to overcome problems with IAIK IXSIL
+ if (currAttr.getOwnerElement() == null)
+ break;
+ if (currClonedElem == null)
+ break;
+
+ // currClonedElem must be the owner Element of currAttr if
+ // preconditions are met
+ currClonedElem.setAttributeNS(
+ currAttr.getNamespaceURI(),
+ currAttr.getNodeName(),
+ currAttr.getValue());
+ break;
+ }
+
+ default :
+ {
+ // All other nodes will be ignored
+ }
+ }
+
+ currPos++;
+ }
+
+ return currPos;
+ }
+
+ /**
+ * Check, if the given attribute is a namespace declaration.
+ *
+ * @param attr The attribute to check.
+ * @return <code>true</code>, if the attribute is a namespace declaration,
+ * <code>false</code> otherwise.
+ */
+ private static boolean isNamespaceDeclaration(Attr attr) {
+ return XMLNamespaceConstants.XMLNS_NS_URI.equals(attr.getNamespaceURI());
+ }
+
+ /**
+ * Check, if a given DOM element is an ancestor of a given node.
+ *
+ * @param candAnc The DOM element to check for being the ancestor.
+ * @param cand The node to check for being the child.
+ * @return <code>true</code>, if <code>candAnc</code> is an (indirect)
+ * ancestor of <code>cand</code>; <code>false</code> otherwise.
+ */
+ public static boolean isAncestor(Element candAnc, Node cand) {
+ Node currPar = cand.getParentNode();
+
+ while (currPar != null) {
+ if (candAnc == currPar)
+ return true;
+ currPar = currPar.getParentNode();
+ }
+ return false;
+ }
+
+ /**
+ * Selects the (first) element from a node list and returns it.
+ *
+ * @param nl The NodeList to get the element from.
+ * @return The (first) element included in the node list or <code>null</code>
+ * if the node list is <code>null</code> or empty or no element is
+ * included in the list.
+ */
+ public static Element getElementFromNodeList (NodeList nl) {
+ if ((nl == null) || (nl.getLength() == 0)) {
+ return null;
+ }
+ for (int i=0; i<nl.getLength(); i++) {
+ Node node = nl.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ return (Element)node;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns all child elements of the given element.
+ *
+ * @param parent The element to get the child elements from.
+ *
+ * @return A list including all child elements of the given element.
+ * Maybe empty if the parent element has no child elements.
+ */
+ public static List getChildElements (Element parent) {
+ Vector v = new Vector();
+ NodeList nl = parent.getChildNodes();
+ int length = nl.getLength();
+ for (int i=0; i < length; i++) {
+ Node node = nl.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ v.add((Element)node);
+ }
+ }
+ return v;
+ }
+
+ /**
+ * Returns a byte array from given node.
+ * @param node
+ * @return
+ * @throws TransformerException
+ */
+ public static byte[] nodeToByteArray(Node node) throws TransformerException {
+ Source source = new DOMSource(node);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ //StringWriter stringWriter = new StringWriter();
+ Result result = new StreamResult(out);
+ TransformerFactory factory = TransformerFactory.newInstance();
+ Transformer transformer = factory.newTransformer();
+ transformer.transform(source, result);
+ return out.toByteArray();
+ }
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java
new file mode 100644
index 00000000..de8fda45
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ ******************************************************************************/
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+
+/**
+ * Builds a DataURL parameter meant for the security layer implementation
+ * to respond to.
+ *
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class DataURLBuilder {
+
+ /**
+ * Constructor for DataURLBuilder.
+ */
+ public DataURLBuilder() {
+ super();
+ }
+
+ /**
+ * Constructs a data URL for <code>VerifyIdentityLink</code> or <code>VerifyAuthenticationBlock</code>,
+ * including the <code>MOASessionID</code> as a parameter.
+ *
+ * @param authBaseURL base URL (context path) of the MOA ID Authentication component,
+ * including a trailing <code>'/'</code>
+ * @param authServletName request part of the data URL
+ * @param pendingReqId sessionID to be included in the dataURL
+ * @return String
+ */
+ public String buildDataURL(String authBaseURL, String authServletName, String pendingReqId) {
+ String dataURL;
+ if (!authBaseURL.endsWith("/"))
+ authBaseURL += "/";
+
+ if (authServletName.startsWith("/"))
+ authServletName = authServletName.substring(1);
+
+ dataURL = authBaseURL + authServletName;
+
+ if (StringUtils.isNotEmpty(pendingReqId))
+ dataURL = addParameter(dataURL, EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReqId);
+
+ return dataURL;
+ }
+
+ /**
+ * Method addParameter.
+ * @param urlString represents the url
+ * @param paramname is the parameter to be added
+ * @param value is the value of that parameter
+ * @return String
+ */
+ private String addParameter(String urlString, String paramname, String value) {
+ String url = urlString;
+ if (paramname != null) {
+ if (url.indexOf("?") < 0)
+ url += "?";
+ else
+ url += "&";
+ url += paramname + "=" + value;
+ }
+ return url;
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java
new file mode 100644
index 00000000..5b39386c
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.InputStream;
+
+import org.apache.xerces.util.URI;
+import org.apache.xerces.util.URI.MalformedURIException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants;
+
+/**
+ * An <code>EntityResolver</code> that looks up entities stored as
+ * local resources.
+ *
+ * <p>The following DTDs are mapped to local resources:
+ * <ul>
+ * <li>The XMLSchema.dtd</li>
+ * <li>The datatypes.dtd</li>
+ * </ul>
+ * </p>
+ * <p>For all other resources, an attempt is made to resolve them as resources,
+ * either absolute or relative to <code>Constants.SCHEMA_ROOT</code>.
+ *
+ */
+public class EAAFDomEntityResolver implements EntityResolver {
+ private static final Logger log = LoggerFactory.getLogger(EAAFDomEntityResolver.class);
+
+ /**
+ * Resolve an entity.
+ *
+ * The <code>systemId</code> parameter is used to perform the lookup of the
+ * entity as a resource, either by interpreting the <code>systemId</code> as
+ * an absolute resource path, or by appending the last path component of
+ * <code>systemId</code> to <code>Constants.SCHEMA_ROOT</code>.
+ *
+ * @param publicId The public ID of the resource.
+ * @param systemId The system ID of the resource.
+ * @return An <code>InputSource</code> from which the entity can be read, or
+ * <code>null</code>, if the entity could not be found.
+ * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String)
+ */
+ public InputSource resolveEntity(String publicId, String systemId) {
+ InputStream stream;
+ int slashPos;
+
+ if (publicId != null) {
+ // check if we can resolve some standard dtd's
+ if (publicId.equalsIgnoreCase("-//W3C//DTD XMLSchema 200102//EN")) {
+ return new InputSource(
+ getClass().getResourceAsStream(
+ XMLNamespaceConstants.SCHEMA_ROOT + "XMLSchema.dtd"));
+ } else if (publicId.equalsIgnoreCase("datatypes")) {
+ return new InputSource(
+ getClass().getResourceAsStream(
+ XMLNamespaceConstants.SCHEMA_ROOT + "datatypes.dtd"));
+ }
+ } else if (systemId != null) {
+ // get the URI path
+ try {
+ URI uri = new URI(systemId);
+ systemId = uri.getPath();
+
+ if (!"file".equals(uri.getScheme()) || "".equals(systemId.trim())) {
+ return null;
+ }
+
+ } catch (MalformedURIException e) {
+ return null;
+ }
+
+ // try to get the resource from the full path
+ stream = getClass().getResourceAsStream(systemId);
+ if (stream != null) {
+ InputSource source = new InputSource(stream);
+
+ source.setSystemId(systemId);
+ return source;
+ }
+
+ // try to get the resource from the last path component
+ slashPos = systemId.lastIndexOf('/');
+ if (slashPos >= 0 && systemId.length() > slashPos) {
+ systemId = systemId.substring(slashPos + 1, systemId.length());
+ stream =
+ getClass().getResourceAsStream(XMLNamespaceConstants.SCHEMA_ROOT + systemId);
+ if (stream != null) {
+ InputSource source = new InputSource(stream);
+
+ source.setSystemId(systemId);
+ return source;
+ }
+ }
+ }
+
+ return null; // nothing found - let the parser handle the entity
+ }
+} \ No newline at end of file
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java
new file mode 100644
index 00000000..01fb7375
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+
+/**
+ * Utility for accessing files on the file system, and for reading from input streams.
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class FileUtils {
+
+ /**
+ * Reads a file, given by URL, into a byte array.
+ * @param urlString file URL
+ * @return file content
+ * @throws IOException on any exception thrown
+ */
+ public static byte[] readURL(String urlString) throws IOException {
+ URL url = new URL(urlString);
+ InputStream in = new BufferedInputStream(url.openStream());
+ byte[] content = StreamUtils.readStream(in);
+ in.close();
+ return content;
+ }
+
+ /**
+ * Reads a file from a resource.
+ * @param name resource name
+ * @return file content as a byte array
+ * @throws IOException on any exception thrown
+ */
+ public static byte[] readResource(String name) throws IOException {
+ ClassLoader cl = FileUtils.class.getClassLoader();
+ BufferedInputStream in = new BufferedInputStream(cl.getResourceAsStream(name));
+ byte[] content = StreamUtils.readStream(in);
+ in.close();
+ return content;
+ }
+ /**
+ * Reads a file from a resource.
+ * @param name filename
+ * @param encoding character encoding
+ * @return file content
+ * @throws IOException on any exception thrown
+ */
+ public static String readResource(String name, String encoding) throws IOException {
+ byte[] content = readResource(name);
+ return new String(content, encoding);
+ }
+
+
+ /**
+ * Returns the absolute URL of a given url which is relative to the parameter root
+ * @param url
+ * @param root
+ * @return String
+ * @throws MalformedURLException
+ */
+ public static String makeAbsoluteURL(String url, URI root) throws MalformedURLException {
+ return makeAbsoluteURL(url, root.toURL().toString());
+
+ }
+
+ /**
+ * Returns the absolute URL of a given url which is relative to the parameter root
+ * @param url
+ * @param root
+ * @return String
+ */
+ public static String makeAbsoluteURL(String url, String root) {
+ //if url is relative to rootConfigFileDirName make it absolute
+
+ File keyFile;
+ String newURL = url;
+
+ if(null == url) return null;
+
+ if (url.startsWith("http:/") || url.startsWith("https:/") || url.startsWith("file:/") || url.startsWith("ftp:/")) {
+ return url;
+
+ } else {
+ // check if absolute - if not make it absolute
+ keyFile = new File(url);
+ if (!keyFile.isAbsolute()) {
+ keyFile = new File(root, url);
+
+ if (keyFile.toString().startsWith("file:"))
+ newURL = keyFile.toString();
+
+ else
+ newURL = keyFile.toURI().toString();
+
+ }
+ return newURL;
+ }
+ }
+
+
+ private static void copy( InputStream fis, OutputStream fos )
+ {
+ try
+ {
+ byte[] buffer = new byte[ 0xFFFF ];
+ for ( int len; (len = fis.read(buffer)) != -1; )
+ fos.write( buffer, 0, len );
+ }
+ catch( IOException e ) {
+ System.err.println( e );
+ }
+ finally {
+ if ( fis != null )
+ try { fis.close(); } catch ( IOException e ) { e.printStackTrace(); }
+ if ( fos != null )
+ try { fos.close(); } catch ( IOException e ) { e.printStackTrace(); }
+ }
+ }
+
+ public static void copyFile(File src, File dest)
+ {
+ try
+ {
+ copy( new FileInputStream( src ), new FileOutputStream( dest ) );
+ }
+ catch( IOException e ) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java
new file mode 100644
index 00000000..cf1abaa7
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ ******************************************************************************/
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang3.StringUtils;
+
+
+/**
+ *
+ * @author Rudolf Schamberger
+ *
+ */
+public class HTTPUtils {
+
+// /**
+// * Utility used to obtainin correct encoded HTTP content.
+// * Reads a given Content adressed by HTTP-URL into String.
+// * Content encoding is considered by using the Content-Type HTTP header charset value.
+// * @param URL HTTP URL to read from.
+// * @return String representation of content
+// * @throws IOException on data-reading problems
+// */
+// public static String readHttpURL(String URL)
+// throws IOException {
+//
+// URL url = new URL(URL);
+// HttpURLConnection conn = (HttpURLConnection)url.openConnection();
+// conn.setRequestMethod("GET");
+// String contentType = conn.getContentType();
+// RE regExp = null;
+// try {
+// regExp = new RE("(;.*charset=)(\"*)(.*[^\"])");
+// } catch (RESyntaxException e) {
+// //RESyntaxException is not possible = expr. is costant
+// }
+// boolean charsetSupplied = regExp.match(contentType);
+// String encoding = "ISO-8859-1"; //default HTTP encoding
+// if (charsetSupplied) {
+// encoding = regExp.getParen(3);
+// }
+// InputStream instream = new BufferedInputStream(conn.getInputStream());
+// InputStreamReader isr = new InputStreamReader(instream, encoding);
+// Reader in = new BufferedReader(isr);
+// int ch;
+// StringBuffer buffer = new StringBuffer();
+// while ((ch = in.read()) > -1) {
+// buffer.append((char)ch);
+// }
+// in.close();
+// conn.disconnect();
+// return buffer.toString();
+// }
+
+ /**
+ * Helper method to retrieve server URL including context path
+ * @param request HttpServletRequest
+ * @return Server URL including context path (e.g. http://localhost:8443/moa-id-auth
+ */
+ public static String getBaseURL(HttpServletRequest request) {
+ StringBuffer buffer = new StringBuffer(getServerURL(request));
+
+ // add context path if available
+ String contextPath = request.getContextPath();
+ if (!StringUtils.isEmpty(contextPath)) {
+ buffer.append(contextPath);
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ * Helper method to retrieve server URL
+ * @param request HttpServletRequest
+ * @return Server URL (e.g. http://localhost:8443)
+ */
+ public static String getServerURL(HttpServletRequest request) {
+ StringBuffer buffer = new StringBuffer();
+
+ // get protocol
+ String protocol = request.getScheme();
+ buffer.append(protocol).append("://");
+
+ // server name
+ buffer.append(request.getServerName());
+
+ // add port if necessary
+ int port = request.getServerPort();
+ if ((protocol.equals("http") && port != 80) || (protocol.equals("https") && port != 443)) {
+ buffer.append(':');
+ buffer.append(port);
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ * Extract the IDP PublicURLPrefix from authrequest
+ *
+ * @param req HttpServletRequest
+ * @return PublicURLPrefix <String> which ends always without /
+ */
+ public static String extractAuthURLFromRequest(HttpServletRequest req) {
+ String authURL = req.getScheme() + "://" + req.getServerName();
+ if ((req.getScheme().equalsIgnoreCase("https") && req.getServerPort()!=443) || (req.getScheme().equalsIgnoreCase("http") && req.getServerPort()!=80)) {
+ authURL = authURL.concat(":" + req.getServerPort());
+ }
+ authURL = authURL.concat(req.getContextPath());
+ return authURL;
+
+ }
+
+ /**
+ * Extract the IDP requested URL from authrequest
+ *
+ * @param req HttpServletRequest
+ * @return RequestURL <String> which ends always without /
+ */
+ public static String extractAuthServletPathFromRequest(HttpServletRequest req) {
+ return extractAuthURLFromRequest(req).concat(req.getServletPath());
+
+ }
+
+ public static String addURLParameter(String url, String paramname,
+ String paramvalue) {
+ String param = paramname + "=" + paramvalue;
+ if (url.indexOf("?") < 0)
+ return url + "?" + param;
+ else
+ return url + "&" + param;
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java
new file mode 100644
index 00000000..3583a294
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+
+/**
+ * Utility for creating and loading key stores.
+ *
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class KeyStoreUtils {
+
+ /**
+ * JAVA KeyStore
+ */
+ private static final String KEYSTORE_TYPE_JKS = "JKS";
+
+ /**
+ * PKCS12 KeyStore
+ */
+ private static final String KEYSTORE_TYPE_PKCS12 = "PKCS12";
+
+
+
+ /**
+ * Loads a key store from file.
+ *
+ * @param keystoreType key store type
+ * @param urlString URL of key store
+ * @param password password protecting the key store
+ * @return key store loaded
+ * @throws IOException thrown while reading the key store from file
+ * @throws GeneralSecurityException thrown while creating the key store
+ */
+ public static KeyStore loadKeyStore(
+ String keystoreType,
+ String urlString,
+ String password)
+ throws IOException, GeneralSecurityException {
+
+ URL keystoreURL = new URL(urlString);
+ InputStream in = keystoreURL.openStream();
+ return loadKeyStore(keystoreType, in, password);
+ }
+ /**
+ * Loads a key store from an <code>InputStream</code>, and
+ * closes the <code>InputStream</code>.
+ *
+ * @param keystoreType key store type
+ * @param in input stream
+ * @param password password protecting the key store
+ * @return key store loaded
+ * @throws IOException thrown while reading the key store from the stream
+ * @throws GeneralSecurityException thrown while creating the key store
+ */
+ public static KeyStore loadKeyStore(
+ String keystoreType,
+ InputStream in,
+ String password)
+ throws IOException, GeneralSecurityException {
+
+ char[] chPassword = null;
+ if (password != null)
+ chPassword = password.toCharArray();
+ KeyStore ks = KeyStore.getInstance(keystoreType);
+ ks.load(in, chPassword);
+ in.close();
+ return ks;
+ }
+ /**
+ * Creates a key store from X509 certificate files, aliasing them with
+ * the index in the <code>String[]</code>, starting with <code>"0"</code>.
+ *
+ * @param keyStoreType key store type
+ * @param certFilenames certificate filenames
+ * @return key store created
+ * @throws IOException thrown while reading the certificates from file
+ * @throws GeneralSecurityException thrown while creating the key store
+ */
+ public static KeyStore createKeyStore(
+ String keyStoreType,
+ String[] certFilenames)
+ throws IOException, GeneralSecurityException {
+
+ KeyStore ks = KeyStore.getInstance(keyStoreType);
+ ks.load(null, null);
+ for (int i = 0; i < certFilenames.length; i++) {
+ Certificate cert = loadCertificate(certFilenames[i]);
+ ks.setCertificateEntry("" + i, cert);
+ }
+ return ks;
+ }
+
+ /**
+ * Loads an X509 certificate from file.
+ * @param certFilename filename
+ * @return the certificate loaded
+ * @throws IOException thrown while reading the certificate from file
+ * @throws GeneralSecurityException thrown while creating the certificate
+ */
+ private static Certificate loadCertificate(String certFilename)
+ throws IOException, GeneralSecurityException {
+
+ FileInputStream in = new FileInputStream(certFilename);
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ Certificate cert = certFactory.generateCertificate(in);
+ in.close();
+ return cert;
+ }
+
+
+ /**
+ * Loads a keyStore without knowing the keyStore type
+ * @param keyStorePath URL to the keyStore
+ * @param password Password protecting the keyStore
+ * @return keyStore loaded
+ * @throws KeyStoreException thrown if keyStore cannot be loaded
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public static KeyStore loadKeyStore(String keyStorePath, String password) throws KeyStoreException, IOException{
+
+ //InputStream is = new FileInputStream(keyStorePath);
+ URL keystoreURL = new URL(keyStorePath);
+ InputStream in = keystoreURL.openStream();
+ InputStream isBuffered = new BufferedInputStream(in);
+ return loadKeyStore(isBuffered, password);
+
+ }
+
+ /**
+ * Loads a keyStore without knowing the keyStore type
+ * @param in input stream
+ * @param password Password protecting the keyStore
+ * @return keyStore loaded
+ * @throws KeyStoreException thrown if keyStore cannot be loaded
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+public static KeyStore loadKeyStore(InputStream is, String password) throws KeyStoreException, IOException{
+ is.mark(1024*1024);
+ KeyStore ks = null;
+ try {
+ try {
+ ks = loadKeyStore(KEYSTORE_TYPE_PKCS12, is, password);
+ } catch (IOException e2) {
+ is.reset();
+ ks = loadKeyStore(KEYSTORE_TYPE_JKS, is, password);
+ }
+ } catch(Exception e) {
+ e.printStackTrace();
+
+ }
+ return ks;
+
+ }
+
+
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java
new file mode 100644
index 00000000..49b957cc
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * @author tlenz
+ *
+ */
+public class KeyValueUtils {
+
+ public static final String KEY_DELIMITER = ".";
+ public static final String CSV_DELIMITER = ",";
+
+ /**
+ * Convert Java properties into a Map<String, String>
+ * <br><br>
+ * <b>Important:</b> The key/values from properties must be of type String!
+ *
+ * @param properties
+ * @return
+ */
+ public static Map<String, String> convertPropertiesToMap(Properties properties) {
+ return new HashMap<String, String>((Map) properties);
+
+ //INFO Java8 solution ;)
+// return properties.entrySet().stream().collect(
+// Collectors.toMap(
+// e -> e.getKey().toString(),
+// e -> e.getValue().toString()
+// )
+// );
+
+ }
+
+ /**
+ * Extract the first child of an input key after a the prefix
+ *
+ * @param key Full input key
+ * @param prefix Prefix
+ * @return Child key {String} if it exists or null
+ */
+ public static String getFirstChildAfterPrefix(String key, String prefix) {
+ String idAfterPrefix = removePrefixFromKey(key, prefix);
+ if (idAfterPrefix != null) {
+ int index = idAfterPrefix.indexOf(KEY_DELIMITER);
+ if (index > 0) {
+ String adding = idAfterPrefix.substring(0, index);
+ if (!(adding.isEmpty())) {
+ return adding;
+
+ }
+ } else if (!(idAfterPrefix.isEmpty())) {
+ return idAfterPrefix;
+
+ }
+
+ }
+ return null;
+ }
+
+ /**
+ * Extract the prefix from an input key
+ *
+ * @param key Full input key
+ * @param suffix Suffix of this key
+ * @return Prefix {String} of the key or null if input key does not ends with postfix string
+ */
+ public static String getPrefixFromKey(String key, String suffix) {
+ if (key != null && key.endsWith(suffix)) {
+ String idPreforeSuffix = key.substring(0, key.length()-suffix.length());
+ if (idPreforeSuffix.endsWith(KEY_DELIMITER))
+ return idPreforeSuffix.substring(0, idPreforeSuffix.length()-1);
+ else
+ return idPreforeSuffix;
+ }
+ return null;
+
+ }
+
+ /**
+ * Remove a prefix string from a key
+ *
+ * @param key Full input key
+ * @param prefix Prefix, which should be removed
+ * @return The suffix of the input key or null if the input does not starts with the prefix
+ */
+ public static String removePrefixFromKey(String key, String prefix) {
+ if (prefix == null)
+ prefix = new String();
+
+ if (key!=null && key.startsWith(prefix)) {
+ String afterPrefix = key.substring(prefix.length());
+ int index = afterPrefix.indexOf(KEY_DELIMITER);
+
+ if (index == 0) {
+ afterPrefix = afterPrefix.substring(1);
+
+ }
+ return afterPrefix;
+
+ }
+ return null;
+ }
+
+ /**
+ * Remove a prefix string from all keys in {Map<String, String>} of key/value pairs
+ *
+ * @param keys Input data of key/value pairs
+ * @param prefix Prefix which should be removed
+ * @return {Map<String, String>} of key/value pairs without prefix in key, but never null
+ */
+ public static Map<String, String> removePrefixFromKeys(Map<String, String> keys, String prefix) {
+ Map<String, String> result = new HashMap<String, String>();
+ Iterator<Entry<String, String>> interator = keys.entrySet().iterator();
+ while(interator.hasNext()) {
+ Entry<String, String> el = interator.next();
+ String newKey = removePrefixFromKey(el.getKey(), prefix);
+ if (StringUtils.isNotEmpty(newKey)) {
+ result.put(newKey, el.getValue());
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Get a subset of key/value pairs which starts with a prefix string
+ * The Prefix is removed from the key
+ *
+ * @param keys Input data of key/value pairs
+ * @param prefix Prefix string
+ * @return {Map<String, String>} of key/value pairs without prefix in key, but never null
+ */
+ public static Map<String, String> getSubSetWithPrefix(Map<String, String> keys, String prefix) {
+ return removePrefixFromKeys(keys, prefix);
+ }
+
+
+ /**
+ * Add a prefix to key/value pairs to make the key absolute according to key namespace convention
+ *
+ * @param input Input key/value pairs which should be updated
+ * @param prefix Key prefix, which should be added if the key is not absolute
+ * @param absolutIdentifier Key identifier, which indicates an absolute key
+ * @return {Map<String, String>} of key/value pairs in which all keys are absolute but never null
+ */
+ public static Map<String, String> makeKeysAbsolut(Map<String, String> input, String prefix, String absolutIdentifier) {
+ Map<String, String> result = new HashMap<String, String>();
+ Iterator<Entry<String, String>> interator = input.entrySet().iterator();
+ while(interator.hasNext()) {
+ Entry<String, String> el = interator.next();
+ if (!el.getKey().startsWith(absolutIdentifier)) {
+ //key is not absolute -> add prefix
+ result.put(prefix
+ + KEY_DELIMITER
+ + el.getKey(),
+ el.getValue());
+
+ } else {
+ //key is absolute
+ result.put(el.getKey(), el.getValue());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get the parent key string from an input key
+ *
+ * @param key input key
+ * @return parent key or the empty String if no parent exists
+ */
+ public static String getParentKey(String key) {
+ if (StringUtils.isNotEmpty(key)) {
+ int index = key.lastIndexOf(KEY_DELIMITER);
+ if (index > 0) {
+ return key.substring(0, index);
+
+ }
+ }
+
+ return new String();
+ }
+
+ /**
+ * Find the highest free list counter
+ *
+ * @param input Array of list keys
+ * @param listPrefix {String} prefix of the list
+ * @return {int} highest free list counter
+ */
+ public static int findNextFreeListCounter(String[] input,
+ String listPrefix) {
+ List<Integer> counters = new ArrayList<Integer>();
+ if (input == null || input.length == 0)
+ return 0;
+
+ else {
+ for (String key : input) {
+ String listIndex = getFirstChildAfterPrefix(key, listPrefix);
+ counters.add(Integer.parseInt(listIndex));
+
+ }
+ Collections.sort(counters);
+ return counters.get(counters.size()-1) + 1;
+ }
+ }
+
+ /**
+ * Find the highest free list counter
+ *
+ * @param keySet {Set<String>} of list keys
+ * @param listPrefix {String} prefix of the list
+ * @return {int} highest free list counter
+ */
+ public static int findNextFreeListCounter(Set<String> keySet,
+ String listPrefix) {
+ if (keySet.isEmpty())
+ return 0;
+
+ String[] array = new String[keySet.size()];
+ keySet.toArray(array);
+ return findNextFreeListCounter(array, listPrefix);
+ }
+
+
+ /**
+ * Normalize a CSV encoded list of value of an key/value pair
+ *
+ * This method removes all whitespace at the begin or the
+ * end of CSV values and remove newLine signs at the end of value.
+ * The ',' is used as list delimiter
+ *
+ * @param value CSV encoded input data
+ * @return normalized CSV encoded data or null if {value} is null or empty
+ */
+ public static String normalizeCSVValueString(String value) {
+ String normalizedCodes = null;
+ if (StringUtils.isNotEmpty(value)) {
+ String[] codes = value.split(CSV_DELIMITER);
+ for (String el: codes) {
+ if (normalizedCodes == null)
+ normalizedCodes = StringUtils.chomp(el.trim());
+ else
+ normalizedCodes += "," + StringUtils.chomp(el.trim());
+
+ }
+ }
+ return normalizedCodes;
+ }
+
+
+ /**
+ * Check a String if it is a comma separated list of values
+ *
+ * This method uses the ',' as list delimiter.
+ *
+ * @param value CSV encoded input data
+ * @return true if the input data contains a ',' and has more then 1 list element, otherwise false
+ */
+ public static boolean isCSVValueString(String value) {
+ if (StringUtils.isNotEmpty(value)) {
+ String[] codes = value.split(CSV_DELIMITER);
+ if (codes.length >= 2) {
+ if (StringUtils.isNotEmpty(codes[1].trim()))
+ return true;
+
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Convert a CSV list to a List of CSV values
+ * <br><br>
+ * This method removes all whitespace at the begin or the
+ * end of CSV values and remove newLine signs at the end of value.
+ * The ',' is used as list delimiter
+ *
+ * @param csv CSV encoded input data
+ * @return List of CSV normalized values, but never null
+ */
+ public static List<String> getListOfCSVValues(String csv) {
+ List<String> list = new ArrayList<String>();
+ if (StringUtils.isNotEmpty(csv)) {
+ String[] values = csv.split(CSV_DELIMITER);
+ for (String el: values)
+ list.add(el.trim());
+
+ }
+
+ return list;
+ }
+
+ /**
+ * This method remove all newline delimiter (\n or \r\n) from input data
+ *
+ * @param value Input String
+ * @return Input String without newline characters
+ */
+ public static String removeAllNewlineFromString(String value) {
+ return value.replaceAll("(\\t|\\r?\\n)+", "");
+
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java
new file mode 100644
index 00000000..c752c91f
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.util.ListIterator;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.NodeIterator;
+
+/**
+ * A <code>NodeIterator</code> implementation based on a
+ * <code>ListIterator</code>.
+ *
+ * @see java.util.ListIterator
+ * @see org.w3c.dom.traversal.NodeIterator
+ *
+ */
+public class NodeIteratorAdapter implements NodeIterator {
+
+ /** The <code>ListIterator</code> to wrap. */
+ private ListIterator nodeIterator;
+
+ /**
+ * Create a new <code>NodeIteratorAdapter</code>.
+ * @param nodeIterator The <code>ListIterator</code> to iterate over.
+ */
+ public NodeIteratorAdapter(ListIterator nodeIterator) {
+ this.nodeIterator = nodeIterator;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#getRoot()
+ */
+ public Node getRoot() {
+ return null;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#getWhatToShow()
+ */
+ public int getWhatToShow() {
+ return NodeFilter.SHOW_ALL;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#getFilter()
+ */
+ public NodeFilter getFilter() {
+ return null;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#getExpandEntityReferences()
+ */
+ public boolean getExpandEntityReferences() {
+ return false;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#nextNode()
+ */
+ public Node nextNode() throws DOMException {
+ if (nodeIterator.hasNext()) {
+ return (Node) nodeIterator.next();
+ }
+ return null;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#previousNode()
+ */
+ public Node previousNode() throws DOMException {
+ if (nodeIterator.hasPrevious()) {
+ return (Node) nodeIterator.previous();
+ }
+ return null;
+ }
+
+ /**
+ * @see org.w3c.dom.traversal.NodeIterator#detach()
+ */
+ public void detach() {
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java
new file mode 100644
index 00000000..61933907
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.util.List;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * A <code>NodeList</code> implementation based on a <code>List</code>.
+ *
+ * @see java.util.List
+ * @see org.w3c.dom.NodeList
+ */
+
+public class NodeListAdapter implements NodeList {
+ /** The <code>List</code> to wrap. */
+ private List nodeList;
+
+ /**
+ * Create a new <code>NodeListAdapter</code>.
+ *
+ * @param nodeList The <code>List</code> containing the nodes.
+ */
+ public NodeListAdapter(List nodeList) {
+ this.nodeList = nodeList;
+ }
+
+ /**
+ * @see org.w3c.dom.NodeList#item(int)
+ */
+ public Node item(int index) {
+ return (Node) nodeList.get(index);
+ }
+
+ /**
+ * @see org.w3c.dom.NodeList#getLength()
+ */
+ public int getLength() {
+ return nodeList.size();
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java
new file mode 100644
index 00000000..aad90649
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ ******************************************************************************/
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+
+import java.nio.ByteBuffer;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.lang3.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Random number generator used to generate ID's
+ * @author Paul Ivancsics
+ * @version $Id$
+ */
+public class Random {
+ private static final Logger log = LoggerFactory.getLogger(Random.class);
+
+ private final static char[] allowedPreFix =
+ {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
+ private static final DateFormat dateFormater = new SimpleDateFormat("yyyyddMM");
+
+ /** random number generator used */
+ private static SecureRandom random;
+ //private static SeedGenerator seedgenerator;
+
+ static {
+ try {
+ random = SecureRandom.getInstance("SHA256PRNG-FIPS186");
+
+ } catch (NoSuchAlgorithmException e) {
+ log.warn("Can NOT initialize SecureRandom with: 'SHA256PRNG-FIPS186'. Use 'StrongSecureRandom' as backup");
+
+ try {
+ random = SecureRandom.getInstanceStrong();
+
+ } catch (NoSuchAlgorithmException e1) {
+ log.error("Can NOT initialize SecureRandom. StartUp process FAILED!");
+ throw new RuntimeException("Can NOT initialize SecureRandom. StartUp process FAILED!", e);
+
+ }
+
+ }
+
+
+ //random = iaik.security.random.SHA256FIPS186Random.getDefault();
+ }
+
+ /**
+ * Generate a unique process reference-value [160bit], which always starts with a letter
+ * <br>
+ * This unique ID consists of single letter, a 64bit date String[yyyyddMM],
+ * and a 88bit random value.
+ *
+ * @return 160bit ID, which is hex encoded
+ */
+ public static String nextProcessReferenceValue() {
+ //pre-process all three parts of a unique reference value
+ String now = dateFormater.format(new Date()); //8 bytes = 64bit
+ byte[] randValue = nextByteRandom(11);
+ char preFix = allowedPreFix[Math.abs(random.nextInt() % allowedPreFix.length)];
+
+ //generate ID
+ String returnValue = preFix + new String(Hex.encodeHex(ArrayUtils.addAll(now.getBytes(), randValue))); // 20 bytes = 160 bits
+ if (returnValue.length() > 40)
+ return returnValue.substring(0, 40);
+ else
+ return returnValue;
+
+ }
+
+
+
+ /**
+ * Creates a new random number [256bit], and encode it as hex value.
+ *
+ * @return random hex encoded value [256bit]
+ */
+ public static String nextHexRandom32() {
+ return new String(Hex.encodeHex(nextByteRandom(32))); // 32 bytes = 256 bits
+
+ }
+
+ /**
+ * Creates a new random number [128bit], and encode it as hex value.
+ *
+ * @return random hex encoded value [128bit]
+ */
+ public static String nextHexRandom16() {
+ return new String(Hex.encodeHex(nextByteRandom(16))); // 16 bytes = 128 bits
+
+ }
+
+ /**
+ * Creates a new random number [64bit], to be used as an ID.
+ *
+ * @return random long as a String [64bit]
+ */
+ public static String nextLongRandom() {
+ return "".concat(String.valueOf(Math.abs(generateLongRandom(32)))); // 32 bytes = 256 bits
+
+ }
+
+ /**
+ * Creates a new random number, to be used as an ID.
+ *
+ * @return random long as a String [64bit]
+ */
+ @Deprecated
+ public static String nextRandom() {
+ long l = ByteBuffer.wrap(nextByteRandom(32)).getLong(); // 32 bytes = 256 bits
+ return "" + Math.abs(l);
+
+ }
+
+/**
+ * Creates a new random byte[]
+ *
+ * @param size Size of random number in byte
+ * @return
+ */
+public static byte[] nextBytes(int size) {
+ return nextByteRandom(size);
+
+}
+
+ public static void seedRandom() {
+ //TODO: implement reflection on IAIK Seed generator
+// seedgenerator = iaik.security.random.AutoSeedGenerator.getDefault();
+// if (seedgenerator.seedAvailable())
+// random.setSeed(seedgenerator.getSeed());
+
+ random.setSeed(System.nanoTime());
+ }
+
+ private static long generateLongRandom(int size) {
+ return ByteBuffer.wrap(nextByteRandom(size)).getLong();
+ }
+
+ /**
+ * Generate a new random number
+ *
+ * @param size Size of random number in byte
+ * @return
+ */
+ private static synchronized byte[] nextByteRandom(int size) {
+ byte[] b = new byte[size];
+ random.nextBytes(b);
+ return b;
+
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java
new file mode 100644
index 00000000..c19e5ab1
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ ******************************************************************************/
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
+
+/**
+ *
+ */
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class ServletUtils {
+
+
+ public static String getBaseUrl( HttpServletRequest request ) {
+ if ( ( request.getServerPort() == 80 ) ||
+ ( request.getServerPort() == 443 ) )
+ return request.getScheme() + "://" +
+ request.getServerName() +
+ request.getContextPath();
+ else
+ return request.getScheme() + "://" +
+ request.getServerName() + ":" + request.getServerPort() +
+ request.getContextPath();
+ }
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java
new file mode 100644
index 00000000..3e4143d4
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * Utility methods for streams.
+ *
+ * @author Patrick Peck
+ * @version $Id$
+ */
+public class StreamUtils {
+
+ /**
+ * Compare the contents of two <code>InputStream</code>s.
+ *
+ * @param is1 The 1st <code>InputStream</code> to compare.
+ * @param is2 The 2nd <code>InputStream</code> to compare.
+ * @return boolean <code>true</code>, if both streams contain the exactly the
+ * same content, <code>false</code> otherwise.
+ * @throws IOException An error occurred reading one of the streams.
+ */
+ public static boolean compareStreams(InputStream is1, InputStream is2)
+ throws IOException {
+
+ byte[] buf1 = new byte[256];
+ byte[] buf2 = new byte[256];
+ int length1;
+ int length2;
+
+ try {
+ while (true) {
+ length1 = is1.read(buf1);
+ length2 = is2.read(buf2);
+
+ if (length1 != length2) {
+ return false;
+ }
+ if (length1 <= 0) {
+ return true;
+ }
+ if (!compareBytes(buf1, buf2, length1)) {
+ return false;
+ }
+ }
+ } catch (IOException e) {
+ throw e;
+ } finally {
+ // close both streams
+ try {
+ is1.close();
+ is2.close();
+ } catch (IOException e) {
+ // ignore this
+ }
+ }
+ }
+
+ /**
+ * Compare two byte arrays, up to a given maximum length.
+ *
+ * @param b1 1st byte array to compare.
+ * @param b2 2nd byte array to compare.
+ * @param length The maximum number of bytes to compare.
+ * @return <code>true</code>, if the byte arrays are equal, <code>false</code>
+ * otherwise.
+ */
+ private static boolean compareBytes(byte[] b1, byte[] b2, int length) {
+ if (b1.length != b2.length) {
+ return false;
+ }
+
+ for (int i = 0; i < b1.length && i < length; i++) {
+ if (b1[i] != b2[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Reads a byte array from a stream.
+ * @param in The <code>InputStream</code> to read.
+ * @return The bytes contained in the given <code>InputStream</code>.
+ * @throws IOException on any exception thrown
+ */
+ public static byte[] readStream(InputStream in) throws IOException {
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copyStream(in, out, null);
+
+ /*
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int b;
+ while ((b = in.read()) >= 0)
+ out.write(b);
+
+ */
+ in.close();
+ return out.toByteArray();
+ }
+
+ /**
+ * Reads a <code>String</code> from a stream, using given encoding.
+ * @param in The <code>InputStream</code> to read.
+ * @param encoding The character encoding to use for converting the bytes
+ * of the <code>InputStream</code> into a <code>String</code>.
+ * @return The content of the given <code>InputStream</code> converted into
+ * a <code>String</code>.
+ * @throws IOException on any exception thrown
+ */
+ public static String readStream(InputStream in, String encoding) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copyStream(in, out, null);
+
+ /*
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int b;
+ while ((b = in.read()) >= 0)
+ out.write(b);
+ */
+ in.close();
+ return out.toString(encoding);
+ }
+
+ /**
+ * Reads all data (until EOF is reached) from the given source to the
+ * destination stream. If the destination stream is null, all data is dropped.
+ * It uses the given buffer to read data and forward it. If the buffer is
+ * null, this method allocates a buffer.
+ *
+ * @param source The stream providing the data.
+ * @param destination The stream that takes the data. If this is null, all
+ * data from source will be read and discarded.
+ * @param buffer The buffer to use for forwarding. If it is null, the method
+ * allocates a buffer.
+ * @exception IOException If reading from the source or writing to the
+ * destination fails.
+ */
+ private static void copyStream(InputStream source, OutputStream destination, byte[] buffer) throws IOException {
+ if (source == null) {
+ throw new NullPointerException("Argument \"source\" must not be null.");
+ }
+ if (buffer == null) {
+ buffer = new byte[8192];
+ }
+
+ if (destination != null) {
+ int bytesRead;
+ while ((bytesRead = source.read(buffer)) >= 0) {
+ destination.write(buffer, 0, bytesRead);
+ }
+ } else {
+ while (source.read(buffer) >= 0);
+ }
+ }
+
+ /**
+ * Gets the stack trace of the <code>Throwable</code> passed in as a string.
+ * @param t The <code>Throwable</code>.
+ * @return a String representing the stack trace of the <code>Throwable</code>.
+ */
+ public static String getStackTraceAsString(Throwable t)
+ {
+ ByteArrayOutputStream stackTraceBIS = new ByteArrayOutputStream();
+ t.printStackTrace(new PrintStream(stackTraceBIS));
+ return new String(stackTraceBIS.toByteArray());
+ }
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java
new file mode 100644
index 00000000..7df211ef
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.core.impl.utils;
+
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+
+/**
+ * @author tlenz
+ *
+ */
+public class TransactionIDUtils {
+
+ //MDC variables for logging
+ public static final String MDC_TRANSACTION_ID = "transactionId";
+ public static final String MDC_SESSION_ID = "sessionId";
+ public static final String MDC_SERVICEPROVIDER_ID = "oaId";
+
+ /**
+ * Set all MDC variables from pending request to this threat context<br>
+ * These includes SessionID, TransactionID, and unique service-provider identifier
+ *
+ * @param pendingRequest
+ */
+ public static void setAllLoggingVariables(IRequest pendingRequest) {
+ setTransactionId(pendingRequest.getUniqueTransactionIdentifier());
+ setSessionId(pendingRequest.getUniqueSessionIdentifier());
+ setServiceProviderId(pendingRequest.getServiceProviderConfiguration().getUniqueIdentifier());
+
+ }
+
+ /**
+ * Remove all MDC variables from this threat context
+ *
+ */
+ public static void removeAllLoggingVariables() {
+ removeSessionId();
+ removeTransactionId();
+ removeServiceProviderId();
+
+ }
+
+
+ public static void setServiceProviderId(String oaUniqueId) {
+ org.apache.log4j.MDC.put(MDC_SERVICEPROVIDER_ID, oaUniqueId);
+ org.slf4j.MDC.put(MDC_SERVICEPROVIDER_ID, oaUniqueId);
+
+ }
+
+ public static void removeServiceProviderId() {
+ org.apache.log4j.MDC.remove(MDC_SERVICEPROVIDER_ID);
+ org.slf4j.MDC.remove(MDC_SERVICEPROVIDER_ID);
+
+ }
+
+ public static void setTransactionId(String pendingRequestID) {
+ org.apache.log4j.MDC.put(MDC_TRANSACTION_ID,
+ "TID-" + pendingRequestID);
+ org.slf4j.MDC.put(MDC_TRANSACTION_ID,
+ "TID-" + pendingRequestID);
+
+ }
+
+ public static void removeTransactionId() {
+ org.apache.log4j.MDC.remove(MDC_TRANSACTION_ID);
+ org.slf4j.MDC.remove(MDC_TRANSACTION_ID);
+
+ }
+
+ public static void setSessionId(String uniqueSessionId) {
+ org.apache.log4j.MDC.put(MDC_SESSION_ID,
+ "SID-" + uniqueSessionId);
+ org.slf4j.MDC.put(MDC_SESSION_ID,
+ "SID-" + uniqueSessionId);
+
+ }
+
+ public static void removeSessionId() {
+ org.apache.log4j.MDC.remove(MDC_SESSION_ID);
+ org.slf4j.MDC.remove(MDC_SESSION_ID);
+
+ }
+
+
+}
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java
new file mode 100644
index 00000000..7df242bd
--- /dev/null
+++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java
@@ -0,0 +1,523 @@
+/*******************************************************************************
+ *******************************************************************************/
+
+
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jaxen.JaxenException;
+import org.jaxen.NamespaceContext;
+import org.jaxen.Navigator;
+import org.jaxen.SimpleNamespaceContext;
+import org.jaxen.dom.DOMXPath;
+import org.jaxen.dom.DocumentNavigator;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.traversal.NodeIterator;
+
+import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants;
+import at.gv.egiz.eaaf.core.exceptions.XPathException;
+
+/**
+ * Utility methods to evaluate XPath expressions on DOM nodes.
+ *
+ * @author Patrick Peck
+ * @version $Id$
+ */
+public class XPathUtils {
+
+ /**
+ * The XPath expression selecting all nodes under a given root (including the
+ * root node itself).
+ */
+ public static final String ALL_NODES_XPATH =
+ "(.//. | .//@* | .//namespace::*)";
+
+ /** The <code>DocumentNavigator</code> to use for navigating the document. */
+ private static Navigator documentNavigator =
+ DocumentNavigator.getInstance();
+ /** The default namespace prefix to namespace URI mappings. */
+ private static NamespaceContext NS_CONTEXT;
+
+ static {
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext();
+ ctx.addNamespace(XMLNamespaceConstants.MOA_PREFIX, XMLNamespaceConstants.MOA_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.MOA_CONFIG_PREFIX, XMLNamespaceConstants.MOA_CONFIG_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.MOA_ID_CONFIG_PREFIX, XMLNamespaceConstants.MOA_ID_CONFIG_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SL10_PREFIX, XMLNamespaceConstants.SL10_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SL11_PREFIX, XMLNamespaceConstants.SL11_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SL12_PREFIX, XMLNamespaceConstants.SL12_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.ECDSA_PREFIX, XMLNamespaceConstants.ECDSA_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.PD_PREFIX, XMLNamespaceConstants.PD_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SAML_PREFIX, XMLNamespaceConstants.SAML_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SAMLP_PREFIX, XMLNamespaceConstants.SAMLP_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.DSIG_PREFIX, XMLNamespaceConstants.DSIG_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.XSLT_PREFIX, XMLNamespaceConstants.XSLT_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.XSI_PREFIX, XMLNamespaceConstants.XSI_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.DSIG_FILTER2_PREFIX, XMLNamespaceConstants.DSIG_FILTER2_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.DSIG_EC_PREFIX, XMLNamespaceConstants.DSIG_EC_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.MD_PREFIX, XMLNamespaceConstants.MD_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.MDP_PREFIX, XMLNamespaceConstants.MDP_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.MVV_PREFIX, XMLNamespaceConstants.MVV_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.STB_PREFIX, XMLNamespaceConstants.STB_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.WRR_PREFIX, XMLNamespaceConstants.WRR_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.STORK_PREFIX, XMLNamespaceConstants.STORK_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.STORKP_PREFIX, XMLNamespaceConstants.STORKP_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SAML2_PREFIX, XMLNamespaceConstants.SAML2_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.SAML2P_PREFIX, XMLNamespaceConstants.SAML2P_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.XENC_PREFIX, XMLNamespaceConstants.XENC_NS_URI);
+ ctx.addNamespace(XMLNamespaceConstants.XADES_1_1_1_NS_PREFIX, XMLNamespaceConstants.XADES_1_1_1_NS_URI);
+ NS_CONTEXT = ctx;
+ }
+
+ /**
+ * Return a <code>NodeIterator</code> over the nodes matching the XPath
+ * expression.
+ *
+ * All namespace URIs and prefixes declared in the <code>Constants</code>
+ * interface are used for resolving namespaces.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return An iterator over the resulting nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeIterator selectNodeIterator(Node contextNode, String exp)
+ throws XPathException {
+
+ return selectNodeIterator(contextNode, NS_CONTEXT, exp);
+ }
+
+ /**
+ * Return a <code>NodeIterator</code> over the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceElement An element from which to build the
+ * namespace mapping for evaluating the XPath expression
+ * @param exp The XPath expression to evaluate.
+ * @return An iterator over the resulting nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeIterator selectNodeIterator(
+ Node contextNode,
+ Element namespaceElement,
+ String exp)
+ throws XPathException {
+
+ try {
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext();
+ ctx.addElementNamespaces(documentNavigator, namespaceElement);
+ return selectNodeIterator(contextNode, ctx, exp);
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Return a <code>NodeIterator</code> over the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceMapping A namespace prefix to namespace URI mapping
+ * (<code>String</code> to <code>String</code>) for evaluating the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return An iterator over the resulting nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeIterator selectNodeIterator(
+ Node contextNode,
+ Map namespaceMapping,
+ String exp)
+ throws XPathException {
+
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping);
+
+ return selectNodeIterator(contextNode, ctx, exp);
+ }
+
+ /**
+ * Return a <code>NodeIterator</code> over the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param nsContext The <code>NamespaceContext</code> for resolving namespace
+ * prefixes to namespace URIs for evaluating the XPath expression.
+ * @param exp The XPath expression to evaluate.
+ * @return An iterator over the resulting nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ private static NodeIterator selectNodeIterator(
+ Node contextNode,
+ NamespaceContext nsContext,
+ String exp)
+ throws XPathException {
+
+ try {
+ DOMXPath xpath = new DOMXPath(exp);
+ List nodes;
+
+ xpath.setNamespaceContext(nsContext);
+ nodes = xpath.selectNodes(contextNode);
+ return new NodeIteratorAdapter(nodes.listIterator());
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Return a <code>NodeList</code> of all the nodes matching the XPath
+ * expression.
+ *
+ * All namespace URIs and prefixes declared in the <code>Constants</code>
+ * interface are used for resolving namespaces.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return A <code>NodeList</code> containing the matching nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeList selectNodeList(Node contextNode, String exp)
+ throws XPathException {
+
+ return selectNodeList(contextNode, NS_CONTEXT, exp);
+ }
+
+ /**
+ * Return a <code>NodeList</code> of all the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceElement An element from which to build the
+ * namespace mapping for evaluating the XPath expression
+ * @param exp The XPath expression to evaluate.
+ * @return A <code>NodeList</code> containing the matching nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeList selectNodeList(
+ Node contextNode,
+ Element namespaceElement,
+ String exp)
+ throws XPathException {
+
+ try {
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext();
+
+ ctx.addElementNamespaces(documentNavigator, namespaceElement);
+ return selectNodeList(contextNode, ctx, exp);
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Return a <code>NodeList</code> of all the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceMapping A namespace prefix to namespace URI mapping
+ * (<code>String</code> to <code>String</code>) for evaluating the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return A <code>NodeList</code> containing the matching nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static NodeList selectNodeList(
+ Node contextNode,
+ Map namespaceMapping,
+ String exp)
+ throws XPathException {
+
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping);
+
+ return selectNodeList(contextNode, ctx, exp);
+ }
+
+ /**
+ * Return a <code>NodeList</code> of all the nodes matching the XPath
+ * expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param nsContext The <code>NamespaceContext</code> for resolving namespace
+ * prefixes to namespace URIs for evaluating the XPath expression.
+ * @param exp The XPath expression to evaluate.
+ * @return A <code>NodeList</code> containing the matching nodes.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ private static NodeList selectNodeList(Node contextNode, NamespaceContext nsContext, String exp) throws XPathException {
+ try {
+ DOMXPath xpath = new DOMXPath(exp);
+ List nodes;
+ xpath.setNamespaceContext(nsContext);
+ nodes = xpath.selectNodes(contextNode);
+ return new NodeListAdapter(nodes);
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Select the first node matching an XPath expression.
+ *
+ * All namespace URIs and prefixes declared in the <code>Constants</code>
+ * interface are used for resolving namespaces.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return Node The first node matching the XPath expression, or
+ * <code>null</code>, if no node matched.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static Node selectSingleNode(Node contextNode, String exp)
+ throws XPathException {
+
+ return selectSingleNode(contextNode, NS_CONTEXT, exp);
+ }
+
+ /**
+ * Select the first node matching an XPath expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceElement An element from which to build the
+ * namespace mapping for evaluating the XPath expression
+ * @param exp The XPath expression to evaluate.
+ * @return Node The first node matching the XPath expression, or
+ * <code>null</code>, if no node matched.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static Node selectSingleNode(
+ Node contextNode,
+ Element namespaceElement,
+ String exp)
+ throws XPathException {
+
+ try {
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext();
+ ctx.addElementNamespaces(documentNavigator, namespaceElement);
+ return selectSingleNode(contextNode, ctx, exp);
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Select the first node matching an XPath expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param namespaceMapping A namespace prefix to namespace URI mapping
+ * (<code>String</code> to <code>String</code>) for evaluating the XPath
+ * expression.
+ * @param exp The XPath expression to evaluate.
+ * @return Node The first node matching the XPath expression, or
+ * <code>null</code>, if no node matched.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static Node selectSingleNode(
+ Node contextNode,
+ Map namespaceMapping,
+ String exp)
+ throws XPathException {
+
+ SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping);
+
+ return selectSingleNode(contextNode, ctx, exp);
+ }
+
+ /**
+ * Select the first node matching an XPath expression.
+ *
+ * @param contextNode The root node from which to evaluate the XPath
+ * expression.
+ * @param nsContext The <code>NamespaceContext</code> for resolving namespace
+ * prefixes to namespace URIs for evaluating the XPath expression.
+ * @param exp The XPath expression to evaluate.
+ * @return Node The first node matching the XPath expression, or
+ * <code>null</code>, if no node matched.
+ * @throws XPathException An error occurred evaluating the XPath expression.
+ */
+ public static Node selectSingleNode(
+ Node contextNode,
+ NamespaceContext nsContext,
+ String exp)
+ throws XPathException {
+
+ try {
+ DOMXPath xpath = new DOMXPath(exp);
+ xpath.setNamespaceContext(nsContext);
+ return (Node) xpath.selectSingleNode(contextNode);
+
+ } catch (JaxenException e) {
+ throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ /**
+ * Return the value of a DOM element whose location is given by an XPath
+ * expression.
+ *
+ * @param root The root element from which to evaluate the XPath.
+ * @param xpath The XPath expression pointing to the element whose value
+ * to return.
+ * @param def The default value to return, if no element can be found using
+ * the given <code>xpath</code>.
+ * @return The element value, if it can be located using the
+ * <code>xpath</code>. Otherwise, <code>def</code> is returned.
+ */
+ public static String getElementValue(
+ Element root,
+ String xpath,
+ String def) {
+
+ Element elem = (Element) XPathUtils.selectSingleNode(root, xpath);
+ return elem != null ? DOMUtils.getText(elem) : def;
+ }
+
+ /**
+ * Return the value of a DOM attribute whose location is given by an XPath
+ * expression.
+ *
+ * @param root The root element from which to evaluate the XPath.
+ * @param xpath The XPath expression pointing to the attribute whose value to
+ * return.
+ * @param def The default value to return, if no attribute can be found using
+ * the given <code>xpath</code>.
+ * @return The element value, if it can be located using the
+ * <code>xpath</code>. Otherwise, <code>def</code> is returned.
+ */
+ public static String getAttributeValue(
+ Element root,
+ String xpath,
+ String def) {
+
+ Attr attr = (Attr) XPathUtils.selectSingleNode(root, xpath);
+ return attr != null ? attr.getValue() : def;
+ }
+
+ /**
+ * Returns the namespace prefix used within <code>XPathUtils</code> for referring to
+ * the namespace of the specified (Security Layer command) element.
+ *
+ * This namespace prefix can be used in various XPath expression evaluation methods
+ * within <code> XPathUtils</code> without explicitely binding it to the particular
+ * namespace.
+ *
+ * @param contextElement The (Security Layer command) element.
+ *
+ * @return the namespace prefix used within <code>XPathUtils</code> for referring to
+ * the namespace of the specified (Security Layer command) element.
+ *
+ * throws XpathException If the specified element has a namespace other than the ones
+ * known by this implementation as valid Security Layer namespaces (cf.
+ * @link Constants#SL10_NS_URI, @link Constants#SL11_NS_URI, @link Constants#SL12_NS_URI).
+ */
+ public static String getSlPrefix (Element contextElement) throws XPathException
+ {
+ String sLNamespace = contextElement.getNamespaceURI();
+ String sLPrefix = null;
+
+ if (sLNamespace.equals(XMLNamespaceConstants.SL10_NS_URI))
+ sLPrefix = XMLNamespaceConstants.SL10_PREFIX;
+
+ else if (sLNamespace.equals(XMLNamespaceConstants.SL12_NS_URI))
+ sLPrefix = XMLNamespaceConstants.SL12_PREFIX;
+
+ else if (sLNamespace.equals(XMLNamespaceConstants.SL11_NS_URI))
+ sLPrefix = XMLNamespaceConstants.SL11_PREFIX;
+
+ else
+ throw new XPathException("XPath operation FAILED. Reason: ");
+
+ return sLPrefix;
+ }
+
+
+ /**
+ * Return the SecurityLayer namespace prefix of the context element.
+ * If the context element is not the element that lies within the
+ * SecurityLayer namespace. The Securitylayer namespace is derived from
+ * the <code>xmlns:sl10</code>, <code>sl11</code> or <code>sl</code>
+ * attribute of the context element.
+ *
+ * The returned prefix is needed for evaluating XPATH expressions.
+ *
+ * @param contextElement The element to get a prefix for the Securitylayer namespace,
+ * that is used within the corresponding document.
+ *
+ * @return The string <code>sl10</code>, <code>sl11</code> or <code>sl</code>,
+ * depending on the SecurityLayer namespace of the contextElement.
+ *
+ * throws XPathException If no (vlalid) SecurityLayer namespace prefix or namespace
+ * is defined.
+ */
+ public static String getSlPrefixFromNoRoot (Element contextElement) throws XPathException {
+
+ String slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL10_PREFIX, XMLNamespaceConstants.SL10_NS_URI);
+ if (slPrefix == null)
+ slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL11_PREFIX, XMLNamespaceConstants.SL11_NS_URI);
+
+ if (slPrefix == null)
+ slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL12_PREFIX, XMLNamespaceConstants.SL12_NS_URI);
+
+ return slPrefix;
+
+ }
+
+ /**
+ * Checks if the context element has an attribute <code>xmlns:slPrefix</code> and
+ * if the prefix of that attribute corresponds with a valid SecurityLayer namespace.
+ *
+ * @param contextElement The element to be checked.
+ * @param slPrefix The prefix which should be checked. Must be a valid SecurityLayer
+ * namespace prefix.
+ * @param slNameSpace The SecurityLayer namespace that corresponds to the specified prefix.
+ *
+ * @return The valid SecurityLayer prefix or <code>null</code> if this prefix is
+ * not used.
+ * @throws XPathException
+ */
+ private static String checkSLnsDeclaration(Element contextElement, String slPrefix, String slNameSpace)
+ throws XPathException
+ {
+ String nsAtt = "xmlns:" + slPrefix;
+ String nameSpace = contextElement.getAttribute(nsAtt);
+ if (nameSpace == "") {
+ return null;
+
+ } else {
+ // check if namespace is correct
+ if (nameSpace.equals(slNameSpace))
+ return slPrefix;
+ else
+ throw new XPathException("Unknown Namespace declaration");
+
+ }
+ }
+
+}